From: Greg Beaver Date: Sun, 20 Jan 2008 00:49:45 +0000 (+0000) Subject: add web-based support for default stub, now phars written with webPhar() will work X-Git-Tag: RELEASE_2_0_0a1~837 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=117f5e2639accd75902b2c3e12cc2495c79441af;p=php add web-based support for default stub, now phars written with webPhar() will work out of the box regardless of server configuration with phar file format split up stub.h strings into 2046 byte chunks because MS VC 6 is friggin stupid --- diff --git a/ext/phar/makestub.php b/ext/phar/makestub.php index 3ce5a5072b..3483874acc 100644 --- a/ext/phar/makestub.php +++ b/ext/phar/makestub.php @@ -1,7 +1,7 @@ '; -$slen = strlen($s) - strlen('index.php'); -//$s = str_replace('XXXX', strlen($s)-1, $s); +$slen = strlen($s) - strlen('index.php') - strlen("000"); +$s = str_replace('\\', '\\\\', $s); $s = str_replace('"', '\\"', $s); $s = str_replace("\n", '\n', $s); +// now we need to find the location of web index file +$webs = substr($s, 0, strpos($s, "000")); +$s = substr($s, strlen($webs) + strlen("000")); $s1 = substr($s, 0, strpos($s, 'index.php')); $s2 = substr($s, strlen($s1) + strlen('index.php')); $s2 = substr($s2, 0, strpos($s2, 'XXXX')); @@ -50,11 +53,63 @@ $stub = '/* /* $Id$ */ -static const char newstub1[] = "' . $s1 . '"; -static const char newstub2[] = "' . $s2 . '"; -static const char newstub3[] = "' . $s3 . '"; -static const int newstub_len = ' . $slen . '; +static inline void phar_get_stub(const char *index_php, const char *web, size_t *len, char **stub, const int name_len, const int web_len TSRMLS_DC) +{ '; +$s1split = str_split($s1, 2046); +$s3split = str_split($s3, 2046); +$took = false; +foreach ($s1split as $i => $chunk) { + if ($took) { + $s1split[$i] = substr($chunk, 1); + $took = false; + } + if ($chunk[strlen($chunk) - 1] == '\\') { + $s1split[$i] .= $s1split[$i + 1][0]; + $took = true; + } +} +foreach ($s3split as $i => $chunk) { + if ($took) { + $s3split[$i] = substr($chunk, 1); + $took = false; + } + if ($chunk[strlen($chunk) - 1] == '\\') { + $s3split[$i] .= $s3split[$i + 1][0]; + $took = true; + } +} +$stub .= "\tstatic const char newstub0[] = \"" . $webs . '"; +'; +foreach ($s1split as $i => $chunk) { + $s1count = $i + 1; + $stub .= "\tstatic const char newstub1_" . $i . '[] = "' . $chunk . '"; +'; +} +$stub .= "\tstatic const char newstub2[] = \"" . $s2 . "\"; +"; +foreach ($s3split as $i => $chunk) { + $s3count = $i + 1; + $stub .= "\tstatic const char newstub3_" . $i . '[] = "' . $chunk . '"; +'; +} +$stub .= " + +\tstatic const int newstub_len = " . $slen . "; + +\t*len = spprintf(stub, name_len + web_len + newstub_len, \"%s%s" . str_repeat('%s', $s1count) . '%s%s%d' + . str_repeat('%s', $s3count) . '", newstub0, web'; +foreach ($s1split as $i => $unused) { + $stub .= ', newstub1_' . $i; +} +$stub .= ', index_php, newstub2'; +$stub .= ", name_len + web_len + newstub_len"; +foreach ($s3split as $i => $unused) { + $stub .= ', newstub3_' . $i; +} +$stub .= "); +} +"; file_put_contents(dirname(__FILE__) . '/stub.h', $stub); ?> \ No newline at end of file diff --git a/ext/phar/phar.c b/ext/phar/phar.c index 5f7d80c64f..06c6977481 100644 --- a/ext/phar/phar.c +++ b/ext/phar/phar.c @@ -2335,12 +2335,14 @@ static int phar_flush_clean_deleted_apply(void *data TSRMLS_DC) /* {{{ */ } /* }}} */ -char *phar_create_default_stub(const char *index_php, size_t *len, char **error TSRMLS_DC) -{ #include "stub.h" + +char *phar_create_default_stub(const char *index_php, const char *web_index, size_t *len, char **error TSRMLS_DC) +{ char *stub = NULL; static const char def[] = "index.php"; - int name_len; + static const char defweb[] = "0"; + int name_len, web_len; size_t dummy; if (!len) { @@ -2350,6 +2352,9 @@ char *phar_create_default_stub(const char *index_php, size_t *len, char **error if (index_php) { name_len = strlen(index_php); } + if (web_index) { + web_len = strlen(web_index); + } if (error) { *error = NULL; } @@ -2360,10 +2365,21 @@ char *phar_create_default_stub(const char *index_php, size_t *len, char **error return NULL; } } - if (!index_php) { - *len = spprintf(&stub, sizeof("index.php")-1 + newstub_len - 1, "%s%s%s%d%s", newstub1, def, newstub2, (int) sizeof("index.php")-1 + newstub_len - 1, newstub3); + if (web_index && web_len > 400) { + /* ridiculous big not allowed for index.php startup filename */ + if (error) { + spprintf(error, 0, "Illegal web filename passed in for stub creation, was %d characters long, and only 400 or less is allowed", web_len); + return NULL; + } + } + if (!index_php && !web_index) { + phar_get_stub(def, defweb, len, &stub, sizeof("index.php")-1, 1 TSRMLS_CC); + } else if (!index_php && web_index ){ + phar_get_stub(def, web_index, len, &stub, sizeof("index.php")-1, web_len+1 TSRMLS_CC); + } else if (index_php && !web_index) { + phar_get_stub(index_php, defweb, len, &stub, name_len+1, 1 TSRMLS_CC); } else { - *len = spprintf(&stub, name_len + newstub_len - 1, "%s%s%s%d%s", newstub1, index_php, newstub2, name_len + newstub_len - 1, newstub3); + phar_get_stub(index_php, web_index, len, &stub, name_len+1, web_len+1 TSRMLS_CC); } return stub; } @@ -2508,7 +2524,7 @@ int phar_flush(phar_archive_data *phar, char *user_stub, long len, char **error } } else { /* this is a brand new phar */ - newstub = phar_create_default_stub(NULL, &(phar->halt_offset), NULL TSRMLS_CC); + newstub = phar_create_default_stub(NULL, NULL, &(phar->halt_offset), NULL TSRMLS_CC); if (phar->halt_offset != php_stream_write(newfile, newstub, phar->halt_offset)) { efree(newstub); if (closeoldfile) { diff --git a/ext/phar/phar_internal.h b/ext/phar/phar_internal.h index e30510011f..213125eec1 100755 --- a/ext/phar/phar_internal.h +++ b/ext/phar/phar_internal.h @@ -336,7 +336,7 @@ int phar_create_or_parse_filename(char *fname, int fname_len, char *alias, int a int phar_open_compiled_file(char *alias, int alias_len, char **error TSRMLS_DC); int phar_get_archive(phar_archive_data **archive, char *fname, int fname_len, char *alias, int alias_len, char **error TSRMLS_DC); int phar_open_loaded(char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, char **error TSRMLS_DC); -char *phar_create_default_stub(const char *index_php, size_t *len, char **error TSRMLS_DC); +char *phar_create_default_stub(const char *index_php, const char *web_index, size_t *len, char **error TSRMLS_DC); char *phar_fix_filepath(char *path, int *new_len, int use_cwd TSRMLS_DC); phar_entry_info * phar_open_jit(phar_archive_data *phar, phar_entry_info *entry, php_stream *fp, diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index 26712263f5..2efb7fb1d4 100755 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -562,7 +562,7 @@ PHP_METHOD(Phar, webPhar) PHAR_SET_MIME("image/jpeg", PHAR_MIME_OTHER, "jpeg") PHAR_SET_MIME("application/x-javascript", PHAR_MIME_OTHER, "js") PHAR_SET_MIME("audio/midi", PHAR_MIME_OTHER, "midi") - PHAR_SET_MIME("audio/midi", PHAR_MIME_OTHER, "midi") + PHAR_SET_MIME("audio/midi", PHAR_MIME_OTHER, "mid") PHAR_SET_MIME("audio/mod", PHAR_MIME_OTHER, "mod") PHAR_SET_MIME("movie/quicktime", PHAR_MIME_OTHER, "mov") PHAR_SET_MIME("audio/mp3", PHAR_MIME_OTHER, "mp3") @@ -735,20 +735,21 @@ PHP_METHOD(Phar, interceptFileFuncs) } /* }}} */ -/* {{ proto array Phar::createDefaultStub([string indexfile]) +/* {{ proto array Phar::createDefaultStub([string indexfile[, string webindexfile]]) * Return a stub that can be used to run a phar-based archive without the phar extension - * indexfile is the startup filename, which defaults to "index.php" + * indexfile is the CLI startup filename, which defaults to "index.php", webindexfile + * is the web startup filename, and also defaults to "index.php" */ PHP_METHOD(Phar, createDefaultStub) { - char *index = NULL, *error; - int index_len; + char *index = NULL, *webindex = NULL, *error; + int index_len, webindex_len; size_t stub_len; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &index, &index_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ss", &index, &index_len, &webindex, &webindex_len) == FAILURE) { return; } - index = phar_create_default_stub(index, &stub_len, &error TSRMLS_CC); + index = phar_create_default_stub(index, webindex, &stub_len, &error TSRMLS_CC); if (error) { zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, error); efree(error); diff --git a/ext/phar/shortarc.php b/ext/phar/shortarc.php index 28b5f28cb3..4e926553c7 100644 --- a/ext/phar/shortarc.php +++ b/ext/phar/shortarc.php @@ -1,4 +1,100 @@ 2, + 'c' => 'text/plain', + 'cc' => 'text/plain', + 'cpp' => 'text/plain', + 'c++' => 'text/plain', + 'dtd' => 'text/plain', + 'h' => 'text/plain', + 'log' => 'text/plain', + 'rng' => 'text/plain', + 'txt' => 'text/plain', + 'xsd' => 'text/plain', + 'php' => 1, + 'inc' => 1, + 'avi' => 'video/avi', + 'bmp' => 'image/bmp', + 'css' => 'text/css', + 'gif' => 'image/gif', + 'htm' => 'text/html', + 'html' => 'text/html', + 'htmls' => 'text/html', + 'ico' => 'image/x-ico', + 'jpe' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'jpeg' => 'image/jpeg', + 'js' => 'application/x-javascript', + 'midi' => 'audio/midi', + 'mid' => 'audio/midi', + 'mod' => 'audio/mod', + 'mov' => 'movie/quicktime', + 'mp3' => 'audio/mp3', + 'mpg' => 'video/mpeg', + 'mpeg' => 'video/mpeg', + 'pdf' => 'application/pdf', + 'png' => 'image/png', + 'swf' => 'application/shockwave-flash', + 'tif' => 'image/tiff', + 'tiff' => 'image/tiff', + 'wav' => 'audio/wav', + 'xbm' => 'image/xbm', + 'xml' => 'text/xml', + ); + $basename = basename(__FILE__); + if (!strpos($_SERVER['REQUEST_URI'], $basename)) { + chdir(Extract_Phar::$temp); + include Extract_Phar::START; + } + $pt = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], $basename) + strlen($basename)); + if (!$pt || $pt == '/') { + $pt = $web; + header('HTTP/1.1 301 Moved Permanently'); + header('Location: ' . $_SERVER['REQUEST_URI'] . '/' . $pt); + } + $a = realpath(Extract_Phar::$temp . DIRECTORY_SEPARATOR . $pt); + if (!$a || strlen(dirname($a)) < strlen(Extract_Phar::$temp)) { + header('HTTP/1.0 404 Not Found'); + echo "\n \n File Not Found<title>\n </head>\n <body>\n <h1>404 - File ", $pt, " Not Found</h1>\n </body>\n</html>"; + exit; + } + $b = pathinfo($a); + if (!isset($b['extension'])) { + header('Content-Type: text/plain'); + header('Content-Length: ' . filesize($a)); + readfile($a); + exit; + } + if (isset($mimes[$b['extension']])) { + if ($mimes[$b['extension']] === 1) { + $_SERVER['PHAR_PATH_INFO'] = $_SERVER['PATH_INFO']; + $_SERVER['PATH_INFO'] = substr($_SERVER['PATH_INFO'], strpos($_SERVER['PATH_INFO'], $basename) + strlen($basename)); + if (isset($_SERVER['PATH_TRANSLATED'])) { + $_SERVER['PHAR_PATH_TRANSLATED'] = $_SERVER['PATH_TRANSLATED']; + $_SERVER['PATH_TRANSLATED'] = $a; + } + include $a; + exit; + } + if ($mimes[$b['extension']] === 2) { + highlight_file($a); + exit; + } + header('Content-Type: ' .$mimes[$b['extension']]); + header('Content-Length: ' . filesize($a)); + readfile($a); + exit; + } +} if (in_array('phar', stream_get_wrappers()) && class_exists('Phar', 0)) { Phar::interceptFileFuncs(); include 'phar://' . __FILE__ . '/' . Extract_Phar::START; @@ -6,18 +102,20 @@ if (in_array('phar', stream_get_wrappers()) && class_exists('Phar', 0)) { } class Extract_Phar { + static $temp; static $tmp = array(); static $origdir; const GZ = 0x1000; const BZ2 = 0x2000; const MASK = 0x3000; const START = 'index.php'; - static function go($D) + const LEN = XXXX; + static function go($return = false) { register_shutdown_function(array('Extract_Phar', '_removeTmpFiles')); $fp = fopen(__FILE__, 'rb'); - fseek($fp, $D); - $L = unpack('V', fread($fp, 4)); + fseek($fp, self::LEN); + $L = unpack('V', $a = fread($fp, 4)); $m = ''; do { $read = 8192; @@ -57,11 +155,14 @@ class Extract_Phar $temp = $sessionpath; } $temp .= '/pharextract'; - if (!file_exists($temp)) { - @mkdir($temp); - $temp = realpath($temp); - self::$tmp[] = $temp; + self::$temp = $temp; + while (file_exists($temp)) { + $temp .= 1; } + @mkdir($temp); + @chmod($temp, 0777); + $temp = realpath($temp); + self::$tmp[] = $temp; self::$origdir = getcwd(); foreach ($info['m'] as $path => $file) { $a = !file_exists(dirname($temp . '/' . $path)); @@ -70,13 +171,15 @@ class Extract_Phar if ($a) self::$tmp[] = realpath(dirname($temp . '/' . $path)); if ($path[strlen($path) - 1] == '/') { mkdir($temp . '/' . $path); + @chmod($temp . '/' . $path, 0777); } else { file_put_contents($temp . '/' . $path, self::extractFile($path, $file, $fp)); + @chmod($temp . '/' . $path, 0666); } self::$tmp[] = realpath($temp . '/' . $path); } chdir($temp); - include self::START; + if (!$return) include self::START; } static function tmpdir() @@ -164,10 +267,8 @@ class Extract_Phar static function _removeTmpFiles() { // for removal of temp files - usort(self::$tmp, 'strnatcasecmp'); - array_reverse(self::$tmp, 1); if (count(self::$tmp)) { - foreach (self::$tmp as $f) { + foreach (array_reverse(self::$tmp) as $f) { if (file_exists($f)) is_dir($f) ? @rmdir($f) : @unlink($f); } diff --git a/ext/phar/stub.h b/ext/phar/stub.h index 74db1fb448..b155c5c9c4 100644 --- a/ext/phar/stub.h +++ b/ext/phar/stub.h @@ -18,7 +18,18 @@ /* $Id$ */ -static const char newstub1[] = "<?php\nif (in_array('phar', stream_get_wrappers()) && class_exists('Phar', 0)) {\nPhar::interceptFileFuncs();\ninclude 'phar://' . __FILE__ . '/' . Extract_Phar::START;\nreturn;\n}\nclass Extract_Phar\n{\nstatic $tmp = array();\nstatic $origdir;\nconst GZ = 0x1000;\nconst BZ2 = 0x2000;\nconst MASK = 0x3000;\nconst START = '"; -static const char newstub2[] = "';\nstatic function go($D)\n{\nregister_shutdown_function(array('Extract_Phar', '_removeTmpFiles'));\n$fp = fopen(__FILE__, 'rb');\nfseek($fp, $D);\n$L = unpack('V', fread($fp, 4));\n$m = '';\ndo {\n$read = 8192;\nif ($L[1] - strlen($m) < 8192) {\n$read = $L[1] - strlen($m);\n}\n$last = fread($fp, $read);\n$m .= $last;\n} while (strlen($last) && strlen($m) < $L[1]);\nif (strlen($m) < $L[1]) {\ndie('ERROR: manifest length read was \"' .\nstrlen($m) .'\" should be \"' .\n$L[1] . '\"');\n}\n$info = self::_unpack($m);\n$f = $info['c'];\nif ($f & self::GZ) {\nif (!function_exists('gzinflate')) {\ndie('Error: zlib extension is not enabled - gzinflate() function needed' .\n' for compressed .phars');\n}\n}\nif ($f & self::BZ2) {\nif (!function_exists('bzdecompress')) {\ndie('Error: bzip2 extension is not enabled - bzdecompress() function needed' .\n' for compressed .phars');\n}\n}\n$temp = self::tmpdir();\nif (!$temp) {\n$sessionpath = session_save_path();\nif (strpos ($sessionpath, \";\") !== FALSE)\n$sessionpath = substr ($sessionpath, strpos ($sessionpath, \";\")+1);\nif (!file_exists($sessionpath) && !is_dir($sessionpath)) {\ndie('Could not locate temporary directory to extract phar');\n}\n$temp = $sessionpath;\n}\n$temp .= '/pharextract';\nif (!file_exists($temp)) {\n@mkdir($temp);\n$temp = realpath($temp);\nself::$tmp[] = $temp;\n}\nself::$origdir = getcwd();\nforeach ($info['m'] as $path => $file) {\n$a = !file_exists(dirname($temp . '/' . $path));\n@mkdir(dirname($temp . '/' . $path), 0777, true);\nclearstatcache();\nif ($a) self::$tmp[] = realpath(dirname($temp . '/' . $path));\nif ($path[strlen($path) - 1] == '/') {\nmkdir($temp . '/' . $path);\n} else {\nfile_put_contents($temp . '/' . $path, self::extractFile($path, $file, $fp));\n}\nself::$tmp[] = realpath($temp . '/' . $path);\n}\nchdir($temp);\ninclude self::START;\n}\n\nstatic function tmpdir()\n{\nif (strpos(PHP_OS, 'WIN') !== false) {\nif ($var = isset($_ENV['TMP']) ? $_ENV['TMP'] : getenv('TMP')) {\nreturn $var;\n}\nif ($var = isset($_ENV['TEMP']) ? $_ENV['TEMP'] : getenv('TEMP')) {\nreturn $var;\n}\nif ($var = isset($_ENV['USERPROFILE']) ? $_ENV['USERPROFILE'] : @getenv('USERPROFILE')) {\nreturn $var;\n}\nif ($var = isset($_ENV['windir']) ? $_ENV['windir'] : getenv('windir')) {\nreturn $var;\n}\nreturn @getenv('SystemRoot') . '\temp';\n}\nif ($var = isset($_ENV['TMPDIR']) ? $_ENV['TMPDIR'] : getenv('TMPDIR')) {\nreturn $var;\n}\nreturn realpath('/tmp');\n}\n\nstatic function _unpack($m)\n{\n$info = unpack('V', substr($m, 0, 4));\n// skip API version, phar flags, alias, metadata\n$l = unpack('V', substr($m, 10, 4));\n$m = substr($m, 14 + $l[1]);\n$s = unpack('V', substr($m, 0, 4));\n$o = 0;\n$start = 4 + $s[1];\n$ret['c'] = 0;\nfor ($i = 0; $i < $info[1]; $i++) {\n// length of the file name\n$len = unpack('V', substr($m, $start, 4));\n$start += 4;\n// file name\n$savepath = substr($m, $start, $len[1]);\n$start += $len[1];\n// retrieve manifest data:\n// 0 = size, 1 = timestamp, 2 = compressed size, 3 = crc32, 4 = flags\n// 5 = metadata length\n$ret['m'][$savepath] = array_values(unpack('Va/Vb/Vc/Vd/Ve/Vf', substr($m, $start, 24)));\n$ret['m'][$savepath][3] = sprintf('%u', $ret['m'][$savepath][3]\n& 0xffffffff);\n$ret['m'][$savepath][7] = $o;\n$o += $ret['m'][$savepath][2];\n$start += 24 + $ret['m'][$savepath][5];\n$ret['c'] |= $ret['m'][$savepath][4] & self::MASK;\n}\nreturn $ret;\n}\n\nstatic function extractFile($path, $entry, $fp)\n{\n$data = '';\n$c = $entry[2];\nwhile ($c) {\nif ($c < 8192) {\n$data .= @fread($fp, $c);\n$c = 0;\n} else {\n$c -= 8192;\n$data .= @fread($fp, 8192);\n}\n}\nif ($entry[4] & self::GZ) {\n$data = gzinflate($data);\n} elseif ($entry[4] & self::BZ2) {\n$data = bzdecompress($data);\n}\nif (strlen($data) != $entry[0]) {\ndie(\"Not valid internal .phar file (size error \" . strlen($data) . \" != \" .\n$stat[7] . \")\");\n}\nif ($entry[3] != sprintf(\"%u\", crc32($data) & 0xffffffff)) {\ndie(\"Not valid internal .phar file (checksum error)\");\n}\nreturn $data;\n}\n\nstatic function _removeTmpFiles()\n{\n// for removal of temp files\nusort(self::$tmp, 'strnatcasecmp');\narray_reverse(self::$tmp, 1);\nif (count(self::$tmp)) {\nforeach (self::$tmp as $f) {\nif (file_exists($f)) is_dir($f) ? @rmdir($f) : @unlink($f);\n}\n\n}\nchdir(self::$origdir);\n}\n}\nExtract_Phar::go("; -static const char newstub3[] = ");\n__HALT_COMPILER(); ?>"; -static const int newstub_len = 4493; +static inline void phar_get_stub(const char *index_php, const char *web, size_t *len, char **stub, const int name_len, const int web_len TSRMLS_DC) +{ + static const char newstub0[] = "<?php\n$web = '"; + static const char newstub1_0[] = "';\nif ($web && in_array('phar', stream_get_wrappers()) && class_exists('Phar', 0)) {\nPhar::interceptFileFuncs();\nPhar::webPhar(null, $web);\ninclude 'phar://' . __FILE__ . '/' . Extract_Phar::START;\nreturn;\n}\nif ($web && isset($_SERVER['REQUEST_URI']) && isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'POST') {\nExtract_Phar::go(true);\n$mimes = array(\n'phps' => 2,\n'c' => 'text/plain',\n'cc' => 'text/plain',\n'cpp' => 'text/plain',\n'c++' => 'text/plain',\n'dtd' => 'text/plain',\n'h' => 'text/plain',\n'log' => 'text/plain',\n'rng' => 'text/plain',\n'txt' => 'text/plain',\n'xsd' => 'text/plain',\n'php' => 1,\n'inc' => 1,\n'avi' => 'video/avi',\n'bmp' => 'image/bmp',\n'css' => 'text/css',\n'gif' => 'image/gif',\n'htm' => 'text/html',\n'html' => 'text/html',\n'htmls' => 'text/html',\n'ico' => 'image/x-ico',\n'jpe' => 'image/jpeg',\n'jpg' => 'image/jpeg',\n'jpeg' => 'image/jpeg',\n'js' => 'application/x-javascript',\n'midi' => 'audio/midi',\n'mid' => 'audio/midi',\n'mod' => 'audio/mod',\n'mov' => 'movie/quicktime',\n'mp3' => 'audio/mp3',\n'mpg' => 'video/mpeg',\n'mpeg' => 'video/mpeg',\n'pdf' => 'application/pdf',\n'png' => 'image/png',\n'swf' => 'application/shockwave-flash',\n'tif' => 'image/tiff',\n'tiff' => 'image/tiff',\n'wav' => 'audio/wav',\n'xbm' => 'image/xbm',\n'xml' => 'text/xml',\n);\n$basename = basename(__FILE__);\nif (!strpos($_SERVER['REQUEST_URI'], $basename)) {\nchdir(Extract_Phar::$temp);\ninclude Extract_Phar::START;\n}\n$pt = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], $basename) + strlen($basename));\nif (!$pt || $pt == '/') {\n$pt = $web;\nheader('HTTP/1.1 301 Moved Permanently');\nheader('Location: ' . $_SERVER['REQUEST_URI'] . '/' . $pt);\n}\n$a = realpath(Extract_Phar::$temp . DIRECTORY_SEPARATOR . $pt);\nif (!$a || strlen(dirname($a)) < strlen(Extract_Phar::$temp)) {\nheader('HTTP/1.0 404 Not Found');\necho \"<html>\\n <head>\\n <title>File Not Found<title>\\n </head>\\n <body>\\n <h1>404 - File \", $p"; + static const char newstub1_1[] = "t, \" Not Found</h1>\\n </body>\\n</html>\";\nexit;\n}\n$b = pathinfo($a);\nif (!isset($b['extension'])) {\nheader('Content-Type: text/plain');\nheader('Content-Length: ' . filesize($a));\nreadfile($a);\nexit;\n}\nif (isset($mimes[$b['extension']])) {\nif ($mimes[$b['extension']] === 1) {\n$_SERVER['PHAR_PATH_INFO'] = $_SERVER['PATH_INFO'];\n$_SERVER['PATH_INFO'] = substr($_SERVER['PATH_INFO'], strpos($_SERVER['PATH_INFO'], $basename) + strlen($basename));\nif (isset($_SERVER['PATH_TRANSLATED'])) {\n$_SERVER['PHAR_PATH_TRANSLATED'] = $_SERVER['PATH_TRANSLATED'];\n$_SERVER['PATH_TRANSLATED'] = $a;\n}\ninclude $a;\nexit;\n}\nif ($mimes[$b['extension']] === 2) {\nhighlight_file($a);\nexit;\n}\nheader('Content-Type: ' .$mimes[$b['extension']]);\nheader('Content-Length: ' . filesize($a));\nreadfile($a);\nexit;\n}\n}\nif (in_array('phar', stream_get_wrappers()) && class_exists('Phar', 0)) {\nPhar::interceptFileFuncs();\ninclude 'phar://' . __FILE__ . '/' . Extract_Phar::START;\nreturn;\n}\nclass Extract_Phar\n{\nstatic $temp;\nstatic $tmp = array();\nstatic $origdir;\nconst GZ = 0x1000;\nconst BZ2 = 0x2000;\nconst MASK = 0x3000;\nconst START = '"; + static const char newstub2[] = "';\nconst LEN = "; + static const char newstub3_0[] = ";\nstatic function go($return = false)\n{\nregister_shutdown_function(array('Extract_Phar', '_removeTmpFiles'));\n$fp = fopen(__FILE__, 'rb');\nfseek($fp, self::LEN);\n$L = unpack('V', $a = fread($fp, 4));\n$m = '';\ndo {\n$read = 8192;\nif ($L[1] - strlen($m) < 8192) {\n$read = $L[1] - strlen($m);\n}\n$last = fread($fp, $read);\n$m .= $last;\n} while (strlen($last) && strlen($m) < $L[1]);\nif (strlen($m) < $L[1]) {\ndie('ERROR: manifest length read was \"' .\nstrlen($m) .'\" should be \"' .\n$L[1] . '\"');\n}\n$info = self::_unpack($m);\n$f = $info['c'];\nif ($f & self::GZ) {\nif (!function_exists('gzinflate')) {\ndie('Error: zlib extension is not enabled - gzinflate() function needed' .\n' for compressed .phars');\n}\n}\nif ($f & self::BZ2) {\nif (!function_exists('bzdecompress')) {\ndie('Error: bzip2 extension is not enabled - bzdecompress() function needed' .\n' for compressed .phars');\n}\n}\n$temp = self::tmpdir();\nif (!$temp) {\n$sessionpath = session_save_path();\nif (strpos ($sessionpath, \";\") !== FALSE)\n$sessionpath = substr ($sessionpath, strpos ($sessionpath, \";\")+1);\nif (!file_exists($sessionpath) && !is_dir($sessionpath)) {\ndie('Could not locate temporary directory to extract phar');\n}\n$temp = $sessionpath;\n}\n$temp .= '/pharextract';\nself::$temp = $temp;\nwhile (file_exists($temp)) {\n$temp .= 1;\n}\n@mkdir($temp);\n@chmod($temp, 0777);\n$temp = realpath($temp);\nself::$tmp[] = $temp;\nself::$origdir = getcwd();\nforeach ($info['m'] as $path => $file) {\n$a = !file_exists(dirname($temp . '/' . $path));\n@mkdir(dirname($temp . '/' . $path), 0777, true);\nclearstatcache();\nif ($a) self::$tmp[] = realpath(dirname($temp . '/' . $path));\nif ($path[strlen($path) - 1] == '/') {\nmkdir($temp . '/' . $path);\n@chmod($temp . '/' . $path, 0777);\n} else {\nfile_put_contents($temp . '/' . $path, self::extractFile($path, $file, $fp));\n@chmod($temp . '/' . $path, 0666);\n}\nself::$tmp[] = realpath($temp . '/' . $path);\n}\nchdir($temp);\nif (!$return) include self::START;\n}\n\nstatic function t"; + static const char newstub3_1[] = "mpdir()\n{\nif (strpos(PHP_OS, 'WIN') !== false) {\nif ($var = isset($_ENV['TMP']) ? $_ENV['TMP'] : getenv('TMP')) {\nreturn $var;\n}\nif ($var = isset($_ENV['TEMP']) ? $_ENV['TEMP'] : getenv('TEMP')) {\nreturn $var;\n}\nif ($var = isset($_ENV['USERPROFILE']) ? $_ENV['USERPROFILE'] : @getenv('USERPROFILE')) {\nreturn $var;\n}\nif ($var = isset($_ENV['windir']) ? $_ENV['windir'] : getenv('windir')) {\nreturn $var;\n}\nreturn @getenv('SystemRoot') . '\\temp';\n}\nif ($var = isset($_ENV['TMPDIR']) ? $_ENV['TMPDIR'] : getenv('TMPDIR')) {\nreturn $var;\n}\nreturn realpath('/tmp');\n}\n\nstatic function _unpack($m)\n{\n$info = unpack('V', substr($m, 0, 4));\n// skip API version, phar flags, alias, metadata\n$l = unpack('V', substr($m, 10, 4));\n$m = substr($m, 14 + $l[1]);\n$s = unpack('V', substr($m, 0, 4));\n$o = 0;\n$start = 4 + $s[1];\n$ret['c'] = 0;\nfor ($i = 0; $i < $info[1]; $i++) {\n// length of the file name\n$len = unpack('V', substr($m, $start, 4));\n$start += 4;\n// file name\n$savepath = substr($m, $start, $len[1]);\n$start += $len[1];\n// retrieve manifest data:\n// 0 = size, 1 = timestamp, 2 = compressed size, 3 = crc32, 4 = flags\n// 5 = metadata length\n$ret['m'][$savepath] = array_values(unpack('Va/Vb/Vc/Vd/Ve/Vf', substr($m, $start, 24)));\n$ret['m'][$savepath][3] = sprintf('%u', $ret['m'][$savepath][3]\n& 0xffffffff);\n$ret['m'][$savepath][7] = $o;\n$o += $ret['m'][$savepath][2];\n$start += 24 + $ret['m'][$savepath][5];\n$ret['c'] |= $ret['m'][$savepath][4] & self::MASK;\n}\nreturn $ret;\n}\n\nstatic function extractFile($path, $entry, $fp)\n{\n$data = '';\n$c = $entry[2];\nwhile ($c) {\nif ($c < 8192) {\n$data .= @fread($fp, $c);\n$c = 0;\n} else {\n$c -= 8192;\n$data .= @fread($fp, 8192);\n}\n}\nif ($entry[4] & self::GZ) {\n$data = gzinflate($data);\n} elseif ($entry[4] & self::BZ2) {\n$data = bzdecompress($data);\n}\nif (strlen($data) != $entry[0]) {\ndie(\"Not valid internal .phar file (size error \" . strlen($data) . \" != \" .\n$stat[7] . \")\");\n}\nif ($entry[3] != sprintf(\"%u\", crc32($"; + static const char newstub3_2[] = "data) & 0xffffffff)) {\ndie(\"Not valid internal .phar file (checksum error)\");\n}\nreturn $data;\n}\n\nstatic function _removeTmpFiles()\n{\n// for removal of temp files\nif (count(self::$tmp)) {\nforeach (array_reverse(self::$tmp) as $f) {\nif (file_exists($f)) is_dir($f) ? @rmdir($f) : @unlink($f);\n}\n\n}\nchdir(self::$origdir);\n}\n}\nExtract_Phar::go();\n__HALT_COMPILER(); ?>"; + + + static const int newstub_len = 7406; + + *len = spprintf(stub, name_len + web_len + newstub_len, "%s%s%s%s%s%s%d%s%s%s", newstub0, web, newstub1_0, newstub1_1, index_php, newstub2, name_len + web_len + newstub_len, newstub3_0, newstub3_1, newstub3_2); +} diff --git a/ext/phar/tests/nophar.phar b/ext/phar/tests/nophar.phar index 04f4384ee1..32f6698966 100644 Binary files a/ext/phar/tests/nophar.phar and b/ext/phar/tests/nophar.phar differ diff --git a/ext/phar/tests/nophar.phar.inc b/ext/phar/tests/nophar.phar.inc index 78867f1a8c..36d5628762 100644 --- a/ext/phar/tests/nophar.phar.inc +++ b/ext/phar/tests/nophar.phar.inc @@ -3,6 +3,8 @@ $fname = dirname(__FILE__) . '/nophar.phar'; @unlink($fname); $p = new Phar($fname); $p['index.php'] = '<?php include "b/c.php";' . "\n"; +$p['web.php'] = '<?php echo "web\n";'; $p['b/c.php'] = '<?php echo "in b\n";$a = fopen("index.php", "r", true);echo stream_get_contents($a);fclose($a);include dirname(__FILE__) . "/../d";'; $p['d'] = "in d\n"; +$p->setStub($p->createDefaultStub('index.php', 'web.php')); ?> \ No newline at end of file diff --git a/ext/phar/tests/nophar_web.phpt b/ext/phar/tests/nophar_web.phpt new file mode 100644 index 0000000000..c255a7001d --- /dev/null +++ b/ext/phar/tests/nophar_web.phpt @@ -0,0 +1,11 @@ +--TEST-- +Phar: default web stub, no phar extension +--SKIPIF-- +<?php if (extension_loaded("phar")) die("skip");?> +--ENV-- +SCRIPT_NAME=/nophar.phar/ +REQUEST_URI=/nophar.phar/ +--FILE_EXTERNAL-- +nophar.phar +--EXPECT-- +web diff --git a/ext/phar/tests/phar_commitwrite.phpt b/ext/phar/tests/phar_commitwrite.phpt index ed786b31af..b461a4ac45 100644 --- a/ext/phar/tests/phar_commitwrite.phpt +++ b/ext/phar/tests/phar_commitwrite.phpt @@ -29,7 +29,103 @@ unlink(dirname(__FILE__) . '/brandnewphar.phar'); __HALT_COMPILER(); ?> --EXPECT-- -string(4501) "<?php +string(7416) "<?php +$web = '0'; +if ($web && in_array('phar', stream_get_wrappers()) && class_exists('Phar', 0)) { +Phar::interceptFileFuncs(); +Phar::webPhar(null, $web); +include 'phar://' . __FILE__ . '/' . Extract_Phar::START; +return; +} +if ($web && isset($_SERVER['REQUEST_URI']) && isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'POST') { +Extract_Phar::go(true); +$mimes = array( +'phps' => 2, +'c' => 'text/plain', +'cc' => 'text/plain', +'cpp' => 'text/plain', +'c++' => 'text/plain', +'dtd' => 'text/plain', +'h' => 'text/plain', +'log' => 'text/plain', +'rng' => 'text/plain', +'txt' => 'text/plain', +'xsd' => 'text/plain', +'php' => 1, +'inc' => 1, +'avi' => 'video/avi', +'bmp' => 'image/bmp', +'css' => 'text/css', +'gif' => 'image/gif', +'htm' => 'text/html', +'html' => 'text/html', +'htmls' => 'text/html', +'ico' => 'image/x-ico', +'jpe' => 'image/jpeg', +'jpg' => 'image/jpeg', +'jpeg' => 'image/jpeg', +'js' => 'application/x-javascript', +'midi' => 'audio/midi', +'mid' => 'audio/midi', +'mod' => 'audio/mod', +'mov' => 'movie/quicktime', +'mp3' => 'audio/mp3', +'mpg' => 'video/mpeg', +'mpeg' => 'video/mpeg', +'pdf' => 'application/pdf', +'png' => 'image/png', +'swf' => 'application/shockwave-flash', +'tif' => 'image/tiff', +'tiff' => 'image/tiff', +'wav' => 'audio/wav', +'xbm' => 'image/xbm', +'xml' => 'text/xml', +); +$basename = basename(__FILE__); +if (!strpos($_SERVER['REQUEST_URI'], $basename)) { +chdir(Extract_Phar::$temp); +include Extract_Phar::START; +} +$pt = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], $basename) + strlen($basename)); +if (!$pt || $pt == '/') { +$pt = $web; +header('HTTP/1.1 301 Moved Permanently'); +header('Location: ' . $_SERVER['REQUEST_URI'] . '/' . $pt); +} +$a = realpath(Extract_Phar::$temp . DIRECTORY_SEPARATOR . $pt); +if (!$a || strlen(dirname($a)) < strlen(Extract_Phar::$temp)) { +header('HTTP/1.0 404 Not Found'); +echo "<html>\n <head>\n <title>File Not Found<title>\n </head>\n <body>\n <h1>404 - File ", $pt, " Not Found</h1>\n </body>\n</html>"; +exit; +} +$b = pathinfo($a); +if (!isset($b['extension'])) { +header('Content-Type: text/plain'); +header('Content-Length: ' . filesize($a)); +readfile($a); +exit; +} +if (isset($mimes[$b['extension']])) { +if ($mimes[$b['extension']] === 1) { +$_SERVER['PHAR_PATH_INFO'] = $_SERVER['PATH_INFO']; +$_SERVER['PATH_INFO'] = substr($_SERVER['PATH_INFO'], strpos($_SERVER['PATH_INFO'], $basename) + strlen($basename)); +if (isset($_SERVER['PATH_TRANSLATED'])) { +$_SERVER['PHAR_PATH_TRANSLATED'] = $_SERVER['PATH_TRANSLATED']; +$_SERVER['PATH_TRANSLATED'] = $a; +} +include $a; +exit; +} +if ($mimes[$b['extension']] === 2) { +highlight_file($a); +exit; +} +header('Content-Type: ' .$mimes[$b['extension']]); +header('Content-Length: ' . filesize($a)); +readfile($a); +exit; +} +} if (in_array('phar', stream_get_wrappers()) && class_exists('Phar', 0)) { Phar::interceptFileFuncs(); include 'phar://' . __FILE__ . '/' . Extract_Phar::START; @@ -37,18 +133,20 @@ return; } class Extract_Phar { +static $temp; static $tmp = array(); static $origdir; const GZ = 0x1000; const BZ2 = 0x2000; const MASK = 0x3000; const START = 'index.php'; -static function go($D) +const LEN = 7416; +static function go($return = false) { register_shutdown_function(array('Extract_Phar', '_removeTmpFiles')); $fp = fopen(__FILE__, 'rb'); -fseek($fp, $D); -$L = unpack('V', fread($fp, 4)); +fseek($fp, self::LEN); +$L = unpack('V', $a = fread($fp, 4)); $m = ''; do { $read = 8192; @@ -88,11 +186,14 @@ die('Could not locate temporary directory to extract phar'); $temp = $sessionpath; } $temp .= '/pharextract'; -if (!file_exists($temp)) { +self::$temp = $temp; +while (file_exists($temp)) { +$temp .= 1; +} @mkdir($temp); +@chmod($temp, 0777); $temp = realpath($temp); self::$tmp[] = $temp; -} self::$origdir = getcwd(); foreach ($info['m'] as $path => $file) { $a = !file_exists(dirname($temp . '/' . $path)); @@ -101,13 +202,15 @@ clearstatcache(); if ($a) self::$tmp[] = realpath(dirname($temp . '/' . $path)); if ($path[strlen($path) - 1] == '/') { mkdir($temp . '/' . $path); +@chmod($temp . '/' . $path, 0777); } else { file_put_contents($temp . '/' . $path, self::extractFile($path, $file, $fp)); +@chmod($temp . '/' . $path, 0666); } self::$tmp[] = realpath($temp . '/' . $path); } chdir($temp); -include self::START; +if (!$return) include self::START; } static function tmpdir() @@ -125,7 +228,7 @@ return $var; if ($var = isset($_ENV['windir']) ? $_ENV['windir'] : getenv('windir')) { return $var; } -return @getenv('SystemRoot') . ' emp'; +return @getenv('SystemRoot') . '\temp'; } if ($var = isset($_ENV['TMPDIR']) ? $_ENV['TMPDIR'] : getenv('TMPDIR')) { return $var; @@ -195,10 +298,8 @@ return $data; static function _removeTmpFiles() { // for removal of temp files -usort(self::$tmp, 'strnatcasecmp'); -array_reverse(self::$tmp, 1); if (count(self::$tmp)) { -foreach (self::$tmp as $f) { +foreach (array_reverse(self::$tmp) as $f) { if (file_exists($f)) is_dir($f) ? @rmdir($f) : @unlink($f); } @@ -206,7 +307,7 @@ if (file_exists($f)) is_dir($f) ? @rmdir($f) : @unlink($f); chdir(self::$origdir); } } -Extract_Phar::go(4501); +Extract_Phar::go(); __HALT_COMPILER(); ?>" string(200) "<?php function __autoload($class) diff --git a/ext/phar/tests/phar_create_in_cwd.phpt b/ext/phar/tests/phar_create_in_cwd.phpt index a54274466b..ece77d9aaf 100644 --- a/ext/phar/tests/phar_create_in_cwd.phpt +++ b/ext/phar/tests/phar_create_in_cwd.phpt @@ -32,7 +32,7 @@ __HALT_COMPILER(); unlink(dirname(__FILE__) . '/brandnewphar.phar'); ?> --EXPECT-- -int(4501) +int(7416) string(200) "<?php function __autoload($class) { diff --git a/ext/phar/tests/phar_createdefaultstub.phpt b/ext/phar/tests/phar_createdefaultstub.phpt index 4629f55bf6..1d59fc2cbe 100644 --- a/ext/phar/tests/phar_createdefaultstub.phpt +++ b/ext/phar/tests/phar_createdefaultstub.phpt @@ -6,16 +6,131 @@ Phar: Phar::createDefaultStub() with and without arg <?php try { var_dump(Phar::createDefaultStub()); +echo "============================================================================\n"; +echo "============================================================================\n"; var_dump(Phar::createDefaultStub('my/custom/thingy.php')); +echo "============================================================================\n"; +echo "============================================================================\n"; var_dump(strlen(Phar::createDefaultStub(str_repeat('a', 400)))); +echo "============================================================================\n"; +echo "============================================================================\n"; var_dump(Phar::createDefaultStub(str_repeat('a', 401))); } catch(Exception $e) { echo $e->getMessage() . "\n"; } +echo "============================================================================\n"; +echo "============================================================================\n"; +echo "============================================================================\n"; +echo "============================================================================\n"; +try { +var_dump(Phar::createDefaultStub('my/custom/thingy.php', 'the/web.php')); +echo "============================================================================\n"; +echo "============================================================================\n"; +var_dump(strlen(Phar::createDefaultStub('index.php', str_repeat('a', 400)))); +var_dump(Phar::createDefaultStub('hio', str_repeat('a', 401))); +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} ?> ===DONE=== --EXPECT-- -string(4501) "<?php +string(7416) "<?php +$web = '0'; +if ($web && in_array('phar', stream_get_wrappers()) && class_exists('Phar', 0)) { +Phar::interceptFileFuncs(); +Phar::webPhar(null, $web); +include 'phar://' . __FILE__ . '/' . Extract_Phar::START; +return; +} +if ($web && isset($_SERVER['REQUEST_URI']) && isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'POST') { +Extract_Phar::go(true); +$mimes = array( +'phps' => 2, +'c' => 'text/plain', +'cc' => 'text/plain', +'cpp' => 'text/plain', +'c++' => 'text/plain', +'dtd' => 'text/plain', +'h' => 'text/plain', +'log' => 'text/plain', +'rng' => 'text/plain', +'txt' => 'text/plain', +'xsd' => 'text/plain', +'php' => 1, +'inc' => 1, +'avi' => 'video/avi', +'bmp' => 'image/bmp', +'css' => 'text/css', +'gif' => 'image/gif', +'htm' => 'text/html', +'html' => 'text/html', +'htmls' => 'text/html', +'ico' => 'image/x-ico', +'jpe' => 'image/jpeg', +'jpg' => 'image/jpeg', +'jpeg' => 'image/jpeg', +'js' => 'application/x-javascript', +'midi' => 'audio/midi', +'mid' => 'audio/midi', +'mod' => 'audio/mod', +'mov' => 'movie/quicktime', +'mp3' => 'audio/mp3', +'mpg' => 'video/mpeg', +'mpeg' => 'video/mpeg', +'pdf' => 'application/pdf', +'png' => 'image/png', +'swf' => 'application/shockwave-flash', +'tif' => 'image/tiff', +'tiff' => 'image/tiff', +'wav' => 'audio/wav', +'xbm' => 'image/xbm', +'xml' => 'text/xml', +); +$basename = basename(__FILE__); +if (!strpos($_SERVER['REQUEST_URI'], $basename)) { +chdir(Extract_Phar::$temp); +include Extract_Phar::START; +} +$pt = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], $basename) + strlen($basename)); +if (!$pt || $pt == '/') { +$pt = $web; +header('HTTP/1.1 301 Moved Permanently'); +header('Location: ' . $_SERVER['REQUEST_URI'] . '/' . $pt); +} +$a = realpath(Extract_Phar::$temp . DIRECTORY_SEPARATOR . $pt); +if (!$a || strlen(dirname($a)) < strlen(Extract_Phar::$temp)) { +header('HTTP/1.0 404 Not Found'); +echo "<html>\n <head>\n <title>File Not Found<title>\n </head>\n <body>\n <h1>404 - File ", $pt, " Not Found</h1>\n </body>\n</html>"; +exit; +} +$b = pathinfo($a); +if (!isset($b['extension'])) { +header('Content-Type: text/plain'); +header('Content-Length: ' . filesize($a)); +readfile($a); +exit; +} +if (isset($mimes[$b['extension']])) { +if ($mimes[$b['extension']] === 1) { +$_SERVER['PHAR_PATH_INFO'] = $_SERVER['PATH_INFO']; +$_SERVER['PATH_INFO'] = substr($_SERVER['PATH_INFO'], strpos($_SERVER['PATH_INFO'], $basename) + strlen($basename)); +if (isset($_SERVER['PATH_TRANSLATED'])) { +$_SERVER['PHAR_PATH_TRANSLATED'] = $_SERVER['PATH_TRANSLATED']; +$_SERVER['PATH_TRANSLATED'] = $a; +} +include $a; +exit; +} +if ($mimes[$b['extension']] === 2) { +highlight_file($a); +exit; +} +header('Content-Type: ' .$mimes[$b['extension']]); +header('Content-Length: ' . filesize($a)); +readfile($a); +exit; +} +} if (in_array('phar', stream_get_wrappers()) && class_exists('Phar', 0)) { Phar::interceptFileFuncs(); include 'phar://' . __FILE__ . '/' . Extract_Phar::START; @@ -23,18 +138,20 @@ return; } class Extract_Phar { +static $temp; static $tmp = array(); static $origdir; const GZ = 0x1000; const BZ2 = 0x2000; const MASK = 0x3000; const START = 'index.php'; -static function go($D) +const LEN = 7416; +static function go($return = false) { register_shutdown_function(array('Extract_Phar', '_removeTmpFiles')); $fp = fopen(__FILE__, 'rb'); -fseek($fp, $D); -$L = unpack('V', fread($fp, 4)); +fseek($fp, self::LEN); +$L = unpack('V', $a = fread($fp, 4)); $m = ''; do { $read = 8192; @@ -74,11 +191,14 @@ die('Could not locate temporary directory to extract phar'); $temp = $sessionpath; } $temp .= '/pharextract'; -if (!file_exists($temp)) { +self::$temp = $temp; +while (file_exists($temp)) { +$temp .= 1; +} @mkdir($temp); +@chmod($temp, 0777); $temp = realpath($temp); self::$tmp[] = $temp; -} self::$origdir = getcwd(); foreach ($info['m'] as $path => $file) { $a = !file_exists(dirname($temp . '/' . $path)); @@ -87,13 +207,15 @@ clearstatcache(); if ($a) self::$tmp[] = realpath(dirname($temp . '/' . $path)); if ($path[strlen($path) - 1] == '/') { mkdir($temp . '/' . $path); +@chmod($temp . '/' . $path, 0777); } else { file_put_contents($temp . '/' . $path, self::extractFile($path, $file, $fp)); +@chmod($temp . '/' . $path, 0666); } self::$tmp[] = realpath($temp . '/' . $path); } chdir($temp); -include self::START; +if (!$return) include self::START; } static function tmpdir() @@ -111,7 +233,7 @@ return $var; if ($var = isset($_ENV['windir']) ? $_ENV['windir'] : getenv('windir')) { return $var; } -return @getenv('SystemRoot') . ' emp'; +return @getenv('SystemRoot') . '\temp'; } if ($var = isset($_ENV['TMPDIR']) ? $_ENV['TMPDIR'] : getenv('TMPDIR')) { return $var; @@ -181,10 +303,8 @@ return $data; static function _removeTmpFiles() { // for removal of temp files -usort(self::$tmp, 'strnatcasecmp'); -array_reverse(self::$tmp, 1); if (count(self::$tmp)) { -foreach (self::$tmp as $f) { +foreach (array_reverse(self::$tmp) as $f) { if (file_exists($f)) is_dir($f) ? @rmdir($f) : @unlink($f); } @@ -192,9 +312,107 @@ if (file_exists($f)) is_dir($f) ? @rmdir($f) : @unlink($f); chdir(self::$origdir); } } -Extract_Phar::go(4501); +Extract_Phar::go(); __HALT_COMPILER(); ?>" -string(4512) "<?php +============================================================================ +============================================================================ +string(7427) "<?php +$web = '0'; +if ($web && in_array('phar', stream_get_wrappers()) && class_exists('Phar', 0)) { +Phar::interceptFileFuncs(); +Phar::webPhar(null, $web); +include 'phar://' . __FILE__ . '/' . Extract_Phar::START; +return; +} +if ($web && isset($_SERVER['REQUEST_URI']) && isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'POST') { +Extract_Phar::go(true); +$mimes = array( +'phps' => 2, +'c' => 'text/plain', +'cc' => 'text/plain', +'cpp' => 'text/plain', +'c++' => 'text/plain', +'dtd' => 'text/plain', +'h' => 'text/plain', +'log' => 'text/plain', +'rng' => 'text/plain', +'txt' => 'text/plain', +'xsd' => 'text/plain', +'php' => 1, +'inc' => 1, +'avi' => 'video/avi', +'bmp' => 'image/bmp', +'css' => 'text/css', +'gif' => 'image/gif', +'htm' => 'text/html', +'html' => 'text/html', +'htmls' => 'text/html', +'ico' => 'image/x-ico', +'jpe' => 'image/jpeg', +'jpg' => 'image/jpeg', +'jpeg' => 'image/jpeg', +'js' => 'application/x-javascript', +'midi' => 'audio/midi', +'mid' => 'audio/midi', +'mod' => 'audio/mod', +'mov' => 'movie/quicktime', +'mp3' => 'audio/mp3', +'mpg' => 'video/mpeg', +'mpeg' => 'video/mpeg', +'pdf' => 'application/pdf', +'png' => 'image/png', +'swf' => 'application/shockwave-flash', +'tif' => 'image/tiff', +'tiff' => 'image/tiff', +'wav' => 'audio/wav', +'xbm' => 'image/xbm', +'xml' => 'text/xml', +); +$basename = basename(__FILE__); +if (!strpos($_SERVER['REQUEST_URI'], $basename)) { +chdir(Extract_Phar::$temp); +include Extract_Phar::START; +} +$pt = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], $basename) + strlen($basename)); +if (!$pt || $pt == '/') { +$pt = $web; +header('HTTP/1.1 301 Moved Permanently'); +header('Location: ' . $_SERVER['REQUEST_URI'] . '/' . $pt); +} +$a = realpath(Extract_Phar::$temp . DIRECTORY_SEPARATOR . $pt); +if (!$a || strlen(dirname($a)) < strlen(Extract_Phar::$temp)) { +header('HTTP/1.0 404 Not Found'); +echo "<html>\n <head>\n <title>File Not Found<title>\n </head>\n <body>\n <h1>404 - File ", $pt, " Not Found</h1>\n </body>\n</html>"; +exit; +} +$b = pathinfo($a); +if (!isset($b['extension'])) { +header('Content-Type: text/plain'); +header('Content-Length: ' . filesize($a)); +readfile($a); +exit; +} +if (isset($mimes[$b['extension']])) { +if ($mimes[$b['extension']] === 1) { +$_SERVER['PHAR_PATH_INFO'] = $_SERVER['PATH_INFO']; +$_SERVER['PATH_INFO'] = substr($_SERVER['PATH_INFO'], strpos($_SERVER['PATH_INFO'], $basename) + strlen($basename)); +if (isset($_SERVER['PATH_TRANSLATED'])) { +$_SERVER['PHAR_PATH_TRANSLATED'] = $_SERVER['PATH_TRANSLATED']; +$_SERVER['PATH_TRANSLATED'] = $a; +} +include $a; +exit; +} +if ($mimes[$b['extension']] === 2) { +highlight_file($a); +exit; +} +header('Content-Type: ' .$mimes[$b['extension']]); +header('Content-Length: ' . filesize($a)); +readfile($a); +exit; +} +} if (in_array('phar', stream_get_wrappers()) && class_exists('Phar', 0)) { Phar::interceptFileFuncs(); include 'phar://' . __FILE__ . '/' . Extract_Phar::START; @@ -202,18 +420,20 @@ return; } class Extract_Phar { +static $temp; static $tmp = array(); static $origdir; const GZ = 0x1000; const BZ2 = 0x2000; const MASK = 0x3000; const START = 'my/custom/thingy.php'; -static function go($D) +const LEN = 7428; +static function go($return = false) { register_shutdown_function(array('Extract_Phar', '_removeTmpFiles')); $fp = fopen(__FILE__, 'rb'); -fseek($fp, $D); -$L = unpack('V', fread($fp, 4)); +fseek($fp, self::LEN); +$L = unpack('V', $a = fread($fp, 4)); $m = ''; do { $read = 8192; @@ -253,11 +473,14 @@ die('Could not locate temporary directory to extract phar'); $temp = $sessionpath; } $temp .= '/pharextract'; -if (!file_exists($temp)) { +self::$temp = $temp; +while (file_exists($temp)) { +$temp .= 1; +} @mkdir($temp); +@chmod($temp, 0777); $temp = realpath($temp); self::$tmp[] = $temp; -} self::$origdir = getcwd(); foreach ($info['m'] as $path => $file) { $a = !file_exists(dirname($temp . '/' . $path)); @@ -266,13 +489,15 @@ clearstatcache(); if ($a) self::$tmp[] = realpath(dirname($temp . '/' . $path)); if ($path[strlen($path) - 1] == '/') { mkdir($temp . '/' . $path); +@chmod($temp . '/' . $path, 0777); } else { file_put_contents($temp . '/' . $path, self::extractFile($path, $file, $fp)); +@chmod($temp . '/' . $path, 0666); } self::$tmp[] = realpath($temp . '/' . $path); } chdir($temp); -include self::START; +if (!$return) include self::START; } static function tmpdir() @@ -290,7 +515,7 @@ return $var; if ($var = isset($_ENV['windir']) ? $_ENV['windir'] : getenv('windir')) { return $var; } -return @getenv('SystemRoot') . ' emp'; +return @getenv('SystemRoot') . '\temp'; } if ($var = isset($_ENV['TMPDIR']) ? $_ENV['TMPDIR'] : getenv('TMPDIR')) { return $var; @@ -360,10 +585,8 @@ return $data; static function _removeTmpFiles() { // for removal of temp files -usort(self::$tmp, 'strnatcasecmp'); -array_reverse(self::$tmp, 1); if (count(self::$tmp)) { -foreach (self::$tmp as $f) { +foreach (array_reverse(self::$tmp) as $f) { if (file_exists($f)) is_dir($f) ? @rmdir($f) : @unlink($f); } @@ -371,8 +594,300 @@ if (file_exists($f)) is_dir($f) ? @rmdir($f) : @unlink($f); chdir(self::$origdir); } } -Extract_Phar::go(4512); +Extract_Phar::go(); __HALT_COMPILER(); ?>" -int(4892) +============================================================================ +============================================================================ +int(7807) +============================================================================ +============================================================================ Illegal filename passed in for stub creation, was 401 characters long, and only 400 or less is allowed -===DONE=== +============================================================================ +============================================================================ +============================================================================ +============================================================================ +string(7437) "<?php +$web = 'the/web.php'; +if ($web && in_array('phar', stream_get_wrappers()) && class_exists('Phar', 0)) { +Phar::interceptFileFuncs(); +Phar::webPhar(null, $web); +include 'phar://' . __FILE__ . '/' . Extract_Phar::START; +return; +} +if ($web && isset($_SERVER['REQUEST_URI']) && isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'POST') { +Extract_Phar::go(true); +$mimes = array( +'phps' => 2, +'c' => 'text/plain', +'cc' => 'text/plain', +'cpp' => 'text/plain', +'c++' => 'text/plain', +'dtd' => 'text/plain', +'h' => 'text/plain', +'log' => 'text/plain', +'rng' => 'text/plain', +'txt' => 'text/plain', +'xsd' => 'text/plain', +'php' => 1, +'inc' => 1, +'avi' => 'video/avi', +'bmp' => 'image/bmp', +'css' => 'text/css', +'gif' => 'image/gif', +'htm' => 'text/html', +'html' => 'text/html', +'htmls' => 'text/html', +'ico' => 'image/x-ico', +'jpe' => 'image/jpeg', +'jpg' => 'image/jpeg', +'jpeg' => 'image/jpeg', +'js' => 'application/x-javascript', +'midi' => 'audio/midi', +'mid' => 'audio/midi', +'mod' => 'audio/mod', +'mov' => 'movie/quicktime', +'mp3' => 'audio/mp3', +'mpg' => 'video/mpeg', +'mpeg' => 'video/mpeg', +'pdf' => 'application/pdf', +'png' => 'image/png', +'swf' => 'application/shockwave-flash', +'tif' => 'image/tiff', +'tiff' => 'image/tiff', +'wav' => 'audio/wav', +'xbm' => 'image/xbm', +'xml' => 'text/xml', +); +$basename = basename(__FILE__); +if (!strpos($_SERVER['REQUEST_URI'], $basename)) { +chdir(Extract_Phar::$temp); +include Extract_Phar::START; +} +$pt = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], $basename) + strlen($basename)); +if (!$pt || $pt == '/') { +$pt = $web; +header('HTTP/1.1 301 Moved Permanently'); +header('Location: ' . $_SERVER['REQUEST_URI'] . '/' . $pt); +} +$a = realpath(Extract_Phar::$temp . DIRECTORY_SEPARATOR . $pt); +if (!$a || strlen(dirname($a)) < strlen(Extract_Phar::$temp)) { +header('HTTP/1.0 404 Not Found'); +echo "<html>\n <head>\n <title>File Not Found<title>\n </head>\n <body>\n <h1>404 - File ", $pt, " Not Found</h1>\n </body>\n</html>"; +exit; +} +$b = pathinfo($a); +if (!isset($b['extension'])) { +header('Content-Type: text/plain'); +header('Content-Length: ' . filesize($a)); +readfile($a); +exit; +} +if (isset($mimes[$b['extension']])) { +if ($mimes[$b['extension']] === 1) { +$_SERVER['PHAR_PATH_INFO'] = $_SERVER['PATH_INFO']; +$_SERVER['PATH_INFO'] = substr($_SERVER['PATH_INFO'], strpos($_SERVER['PATH_INFO'], $basename) + strlen($basename)); +if (isset($_SERVER['PATH_TRANSLATED'])) { +$_SERVER['PHAR_PATH_TRANSLATED'] = $_SERVER['PATH_TRANSLATED']; +$_SERVER['PATH_TRANSLATED'] = $a; +} +include $a; +exit; +} +if ($mimes[$b['extension']] === 2) { +highlight_file($a); +exit; +} +header('Content-Type: ' .$mimes[$b['extension']]); +header('Content-Length: ' . filesize($a)); +readfile($a); +exit; +} +} +if (in_array('phar', stream_get_wrappers()) && class_exists('Phar', 0)) { +Phar::interceptFileFuncs(); +include 'phar://' . __FILE__ . '/' . Extract_Phar::START; +return; +} +class Extract_Phar +{ +static $temp; +static $tmp = array(); +static $origdir; +const GZ = 0x1000; +const BZ2 = 0x2000; +const MASK = 0x3000; +const START = 'my/custom/thingy.php'; +const LEN = 7439; +static function go($return = false) +{ +register_shutdown_function(array('Extract_Phar', '_removeTmpFiles')); +$fp = fopen(__FILE__, 'rb'); +fseek($fp, self::LEN); +$L = unpack('V', $a = fread($fp, 4)); +$m = ''; +do { +$read = 8192; +if ($L[1] - strlen($m) < 8192) { +$read = $L[1] - strlen($m); +} +$last = fread($fp, $read); +$m .= $last; +} while (strlen($last) && strlen($m) < $L[1]); +if (strlen($m) < $L[1]) { +die('ERROR: manifest length read was "' . +strlen($m) .'" should be "' . +$L[1] . '"'); +} +$info = self::_unpack($m); +$f = $info['c']; +if ($f & self::GZ) { +if (!function_exists('gzinflate')) { +die('Error: zlib extension is not enabled - gzinflate() function needed' . +' for compressed .phars'); +} +} +if ($f & self::BZ2) { +if (!function_exists('bzdecompress')) { +die('Error: bzip2 extension is not enabled - bzdecompress() function needed' . +' for compressed .phars'); +} +} +$temp = self::tmpdir(); +if (!$temp) { +$sessionpath = session_save_path(); +if (strpos ($sessionpath, ";") !== FALSE) +$sessionpath = substr ($sessionpath, strpos ($sessionpath, ";")+1); +if (!file_exists($sessionpath) && !is_dir($sessionpath)) { +die('Could not locate temporary directory to extract phar'); +} +$temp = $sessionpath; +} +$temp .= '/pharextract'; +self::$temp = $temp; +while (file_exists($temp)) { +$temp .= 1; +} +@mkdir($temp); +@chmod($temp, 0777); +$temp = realpath($temp); +self::$tmp[] = $temp; +self::$origdir = getcwd(); +foreach ($info['m'] as $path => $file) { +$a = !file_exists(dirname($temp . '/' . $path)); +@mkdir(dirname($temp . '/' . $path), 0777, true); +clearstatcache(); +if ($a) self::$tmp[] = realpath(dirname($temp . '/' . $path)); +if ($path[strlen($path) - 1] == '/') { +mkdir($temp . '/' . $path); +@chmod($temp . '/' . $path, 0777); +} else { +file_put_contents($temp . '/' . $path, self::extractFile($path, $file, $fp)); +@chmod($temp . '/' . $path, 0666); +} +self::$tmp[] = realpath($temp . '/' . $path); +} +chdir($temp); +if (!$return) include self::START; +} + +static function tmpdir() +{ +if (strpos(PHP_OS, 'WIN') !== false) { +if ($var = isset($_ENV['TMP']) ? $_ENV['TMP'] : getenv('TMP')) { +return $var; +} +if ($var = isset($_ENV['TEMP']) ? $_ENV['TEMP'] : getenv('TEMP')) { +return $var; +} +if ($var = isset($_ENV['USERPROFILE']) ? $_ENV['USERPROFILE'] : @getenv('USERPROFILE')) { +return $var; +} +if ($var = isset($_ENV['windir']) ? $_ENV['windir'] : getenv('windir')) { +return $var; +} +return @getenv('SystemRoot') . '\temp'; +} +if ($var = isset($_ENV['TMPDIR']) ? $_ENV['TMPDIR'] : getenv('TMPDIR')) { +return $var; +} +return realpath('/tmp'); +} + +static function _unpack($m) +{ +$info = unpack('V', substr($m, 0, 4)); +// skip API version, phar flags, alias, metadata +$l = unpack('V', substr($m, 10, 4)); +$m = substr($m, 14 + $l[1]); +$s = unpack('V', substr($m, 0, 4)); +$o = 0; +$start = 4 + $s[1]; +$ret['c'] = 0; +for ($i = 0; $i < $info[1]; $i++) { +// length of the file name +$len = unpack('V', substr($m, $start, 4)); +$start += 4; +// file name +$savepath = substr($m, $start, $len[1]); +$start += $len[1]; +// retrieve manifest data: +// 0 = size, 1 = timestamp, 2 = compressed size, 3 = crc32, 4 = flags +// 5 = metadata length +$ret['m'][$savepath] = array_values(unpack('Va/Vb/Vc/Vd/Ve/Vf', substr($m, $start, 24))); +$ret['m'][$savepath][3] = sprintf('%u', $ret['m'][$savepath][3] +& 0xffffffff); +$ret['m'][$savepath][7] = $o; +$o += $ret['m'][$savepath][2]; +$start += 24 + $ret['m'][$savepath][5]; +$ret['c'] |= $ret['m'][$savepath][4] & self::MASK; +} +return $ret; +} + +static function extractFile($path, $entry, $fp) +{ +$data = ''; +$c = $entry[2]; +while ($c) { +if ($c < 8192) { +$data .= @fread($fp, $c); +$c = 0; +} else { +$c -= 8192; +$data .= @fread($fp, 8192); +} +} +if ($entry[4] & self::GZ) { +$data = gzinflate($data); +} elseif ($entry[4] & self::BZ2) { +$data = bzdecompress($data); +} +if (strlen($data) != $entry[0]) { +die("Not valid internal .phar file (size error " . strlen($data) . " != " . +$stat[7] . ")"); +} +if ($entry[3] != sprintf("%u", crc32($data) & 0xffffffff)) { +die("Not valid internal .phar file (checksum error)"); +} +return $data; +} + +static function _removeTmpFiles() +{ +// for removal of temp files +if (count(self::$tmp)) { +foreach (array_reverse(self::$tmp) as $f) { +if (file_exists($f)) is_dir($f) ? @rmdir($f) : @unlink($f); +} + +} +chdir(self::$origdir); +} +} +Extract_Phar::go(); +__HALT_COMPILER(); ?>" +============================================================================ +============================================================================ +int(7815) +Illegal web filename passed in for stub creation, was 401 characters long, and only 400 or less is allowed +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/withphar_web.phpt b/ext/phar/tests/withphar_web.phpt new file mode 100644 index 0000000000..887150de79 --- /dev/null +++ b/ext/phar/tests/withphar_web.phpt @@ -0,0 +1,13 @@ +--TEST-- +Phar: default web stub, with phar extension +--SKIPIF-- +<?php if (!extension_loaded("phar")) die("skip");?> +--ENV-- +SCRIPT_NAME=/withphar_web.php/web.php +REQUEST_URI=/withphar_web.php/web.php +--FILE_EXTERNAL-- +nophar.phar +--EXPECTHEADERS-- +Content-type: text/html +--EXPECT-- +web