Pull to refresh

Делаем самораспаковывающийся архив или секции в PHP файлах

Reading time4 min
Views1.3K
Побудила писать этот код меня только одна вещь — тупые FTP некоторых хостеров.
Нет, файлы заливаются с максимальной скоростью, но вот между окончанием загрузки одного файла и началом загрузки следующего проходит секунд 30.
Так как я сейчас страдаю хренью верстаю и ставлю джомлы в ударных количествах, загрузка 5000+ файлов приводит к зачитыванию хабры и гуглридера до дыр, что однако тоже вредно для здоровья.
С целью исправить сиё досадное упущение и пишется небольшой наколеночный скриптик.



Скриптик как известно штука такая что его не только на сервере, но и из консоли запускать можно, а значит надо предусмотреть работоспособность обоих вариантов.
Для определения консоли используется isset($argv)
Собственно сам код упаковки и распаковки не интересен.
А вот на что я бы хотел обратить внимание %username% так на то как именно организован упаковщик.
Для этого рассказываю про одну функцию и одну константу о которой не знают не только школьники и индусы.

Это функция __compiler_halt и константа __COMPILER_HALT_OFFSET__, обе введены в PHP начиная с 5.1
При парсинге файла если php натыкается на __compiler_halt(); то он завершает парсинг и выставляет в __COMPILER_HALT_OFFSET__ номер байта следующего за точкой с запятой после имени функции
Важно понимать что никаких ?> уже не требуется после этой конструкции
Что же это нам даёт?
А даёт это нам возможность хранить всякую дрянь произвольные данные в нашем php коде
Причём считываются эти данные очень легко: file_get_contents(__FILE__,null,null,__COMPILER_HALT_OFFSET__);
Если это использовать файл получается разбитым на 2 секции — секцию кода и секцию данных

Упаковщик содержит в секции кода код упаковки, а в секции данных код распаковки
Распаковщик же в секции кода содержит себя любимого, а в секции данных — zip архив c данными

Не надоедая дальнейшими разглагольствованиями привожу код:

<?php

$packname 
getcwd().'/'.basename(__FILE__,'.php').'.packed.php';
$zip = new ZipArchive();
$zip->open($packnameZIPARCHIVE::CREATE|ZIPARCHIVE::OVERWRITE);
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator('./'));
$packer realpath(__FILE__);
foreach(
$iterator as $key=>$value)
{
    
$file realpath($key);
    if(
$file!=$packer)
    
$zip->addFile($file,$key);
}
$zip->close();

$data file_get_contents(__FILE__,null,null,__COMPILER_HALT_OFFSET__);
$zipped = @file_get_contents($packname);
if(
$zipped=='') die();
file_put_contents($packname,$data.$zipped);

__halt_compiler();<?
php
$mode 
'';
if(isset(
$argv[1]))
{
    
$mode $argv[1];
}
if(isset(
$_REQUEST['mode']))
{
    
$mode $_REQUEST['mode'];
}
function 
extract_archive()
{
    
file_put_contents(getcwd().'/'.basename(__FILE__).'.zip',file_get_contents(__FILE__,null,null,__COMPILER_HALT_OFFSET__));
}
$file basename(__FILE__);
if(!isset(
$argv))
echo <<<HEREDOC
<html>
<head>
<title>Упакованный архив $file</title>
</head>
<body style="font-size:24px;">
HEREDOC;
switch(
$mode)
{
    case 
'extract':
    
extract_archive();
    echo 
"Извлечён\n";
    break;
    case 
'unpack':
    
extract_archive();
    
$zip = new ZipArchive;
    
$zip->open(getcwd().'/'.basename(__FILE__).'.zip');
    
$zip->extractTo('./');
    
$zip->close();
    
unlink(getcwd().'/'.basename(__FILE__).'.zip');
    
unlink(__FILE__);
    echo 
"Распакован\n";
    break;
    default:
    
    if(isset(
$argv))
    {
    echo <<<HEREDOC
Extract me with
    php $file extract
Unpack me with
    php $file unpack

HEREDOC;
    }
    else
    {
        echo 
'<a href="?mode=unpack">Распаковать архив</a><br><a href="?mode=extract">Извлечь архив</a>';
    }
}
if(!isset(
$argv)) echo '</body></html>';
__halt_compiler();




ну, на сегодя это всё что я хотел сказать, разве что нарушая традиции попрошу попинать ногами за косяки в первом посте на хабре, иначе будет поздно :)
Tags:
Hubs:
Total votes 41: ↑34 and ↓7+27
Comments8

Articles