From: Greg Beaver Date: Fri, 18 Jan 2008 05:42:16 +0000 (+0000) Subject: major improvement: X-Git-Tag: RELEASE_2_0_0a1~850 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7540adf0581064933077a128658d278ce6eba2d0;p=php major improvement: the new default stub allows creation of phars that run identically 1) with Phar extension 2) without Phar extension 3) extracted to disk from the phar this makes the default phar format quite interesting as it eliminates the only drawback of the extension --- diff --git a/ext/phar/makestub.php b/ext/phar/makestub.php new file mode 100644 index 0000000000..4296cab2d5 --- /dev/null +++ b/ext/phar/makestub.php @@ -0,0 +1,51 @@ +'; +$s = str_replace('XXXX', strlen($s)-1, $s); +$s = str_replace('"', '\\"', $s); +$s = str_replace("\n", '\n', $s); + +$stub = '/* + +----------------------------------------------------------------------+ + | phar php single-file executable PHP extension generated stub | + +----------------------------------------------------------------------+ + | Copyright (c) 2005-' . date('Y') . ' The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Gregory Beaver | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +static const char newstub[] = "' . $s . '"; +'; + +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 92c63dd5d6..38f3f75bc1 100644 --- a/ext/phar/phar.c +++ b/ext/phar/phar.c @@ -2343,7 +2343,8 @@ static int phar_flush_clean_deleted_apply(void *data TSRMLS_DC) /* {{{ */ */ int phar_flush(phar_archive_data *phar, char *user_stub, long len, char **error TSRMLS_DC) /* {{{ */ { - static const char newstub[] = "\r\n"; +#include "stub.h" +/* static const char newstub[] = "\r\n"; */ phar_entry_info *entry, *newentry; int halt_offset, restore_alias_len, global_flags = 0, closeoldfile; char *buf, *pos; @@ -3199,12 +3200,12 @@ PHP_MINIT_FUNCTION(phar) /* {{{ */ phar_has_bz2 = zend_hash_exists(&module_registry, "bz2", sizeof("bz2")); phar_has_zlib = zend_hash_exists(&module_registry, "zlib", sizeof("zlib")); if (SUCCESS == zend_hash_find(&module_registry, "zip", sizeof("zip"), (void **) &test)) { - if (strlen(test->version) == sizeof("1.8.11")-1 && !strncmp(test->version, "1.8.11", sizeof("1.8.11")-1)) { + if (php_version_compare((const char *) test->version, "1.8.11") != -1) { phar_has_zip = 1; } else { phar_has_zip = 0; } - phar_zip_ver = test->version; + phar_zip_ver = (char *) test->version; } else { phar_has_zip = 0; phar_zip_ver = NULL; diff --git a/ext/phar/phar_internal.h b/ext/phar/phar_internal.h index 4fc713ae46..82a60d9674 100755 --- a/ext/phar/phar_internal.h +++ b/ext/phar/phar_internal.h @@ -54,6 +54,7 @@ #include "ext/standard/sha1.h" #include "ext/standard/php_var.h" #include "ext/standard/php_smart_str.h" +#include "ext/standard/php_versioning.h" #ifndef PHP_WIN32 #include "TSRM/tsrm_strtok_r.h" #endif diff --git a/ext/phar/shortarc.php b/ext/phar/shortarc.php new file mode 100644 index 0000000000..5ab57577a3 --- /dev/null +++ b/ext/phar/shortarc.php @@ -0,0 +1,176 @@ + $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); + } else { + file_put_contents($temp . '/' . $path, self::extractFile($path, $file, $fp)); + } + self::$tmp[] = realpath($temp . '/' . $path); + } + chdir($temp); + include 'index.php'; + } + + 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 + usort(self::$tmp, 'strnatcasecmp'); + array_reverse(self::$tmp, 1); + if (count(self::$tmp)) { + foreach (self::$tmp as $f) { + if (file_exists($f)) is_dir($f) ? @rmdir($f) : @unlink($f); + } + + } + chdir(self::$origdir); + } +} \ No newline at end of file diff --git a/ext/phar/stream.c b/ext/phar/stream.c index ef0bdf0f5b..cf24b5045d 100644 --- a/ext/phar/stream.c +++ b/ext/phar/stream.c @@ -65,7 +65,9 @@ php_url* phar_open_url(php_stream_wrapper *wrapper, char *filename, char *mode, if (!strncasecmp(filename, "phar://", 7)) { if (mode[0] == 'a') { - php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: open mode append not supported"); + if (!(options & PHP_STREAM_URL_STAT_QUIET)) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: open mode append not supported"); + } return NULL; } if (phar_split_fname(filename, strlen(filename), &arch, &arch_len, &entry, &entry_len TSRMLS_CC) == FAILURE) { @@ -108,14 +110,18 @@ php_url* phar_open_url(php_stream_wrapper *wrapper, char *filename, char *mode, } if (mode[0] == 'w' || (mode[0] == 'r' && mode[1] == '+')) { if (PHAR_G(readonly)) { - php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: write operations disabled by INI setting"); + if (!(options & PHP_STREAM_URL_STAT_QUIET)) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: write operations disabled by INI setting"); + } php_url_free(resource); return NULL; } if (phar_open_or_create_filename(resource->host, arch_len, NULL, 0, options, NULL, &error TSRMLS_CC) == FAILURE) { if (error) { - php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, error); + if (!(options & PHP_STREAM_URL_STAT_QUIET)) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, error); + } efree(error); } php_url_free(resource); @@ -125,7 +131,9 @@ php_url* phar_open_url(php_stream_wrapper *wrapper, char *filename, char *mode, if (phar_open_filename(resource->host, arch_len, NULL, 0, options, NULL, &error TSRMLS_CC) == FAILURE) { if (error) { - php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, error); + if (!(options & PHP_STREAM_URL_STAT_QUIET)) { + php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, error); + } efree(error); } php_url_free(resource); diff --git a/ext/phar/stub.h b/ext/phar/stub.h new file mode 100644 index 0000000000..7f42a99f9c --- /dev/null +++ b/ext/phar/stub.h @@ -0,0 +1,21 @@ +/* + +----------------------------------------------------------------------+ + | phar php single-file executable PHP extension generated stub | + +----------------------------------------------------------------------+ + | Copyright (c) 2005-2008 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Gregory Beaver | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +static const char newstub[] = " $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 'index.php';\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(4461);\n__HALT_COMPILER(); ?>"; diff --git a/ext/phar/tests/nophar.phar b/ext/phar/tests/nophar.phar new file mode 100644 index 0000000000..e3235b28f6 Binary files /dev/null and b/ext/phar/tests/nophar.phar differ diff --git a/ext/phar/tests/nophar.phar.inc b/ext/phar/tests/nophar.phar.inc new file mode 100644 index 0000000000..78867f1a8c --- /dev/null +++ b/ext/phar/tests/nophar.phar.inc @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/ext/phar/tests/nophar.phpt b/ext/phar/tests/nophar.phpt new file mode 100644 index 0000000000..2b7af7ac63 --- /dev/null +++ b/ext/phar/tests/nophar.phpt @@ -0,0 +1,14 @@ +--TEST-- +Phar: phar run without pecl/phar with default stub +--SKIPIF-- + +--FILE-- + +===DONE=== +--EXPECT-- +in b +getStub()); --CLEAN-- --EXPECT-- -string(29) " -" +string(4461) " $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); +} else { +file_put_contents($temp . '/' . $path, self::extractFile($path, $file, $fp)); +} +self::$tmp[] = realpath($temp . '/' . $path); +} +chdir($temp); +include 'index.php'; +} + +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') . ' emp'; +} +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 +usort(self::$tmp, 'strnatcasecmp'); +array_reverse(self::$tmp, 1); +if (count(self::$tmp)) { +foreach (self::$tmp as $f) { +if (file_exists($f)) is_dir($f) ? @rmdir($f) : @unlink($f); +} + +} +chdir(self::$origdir); +} +} +Extract_Phar::go(4433); +__HALT_COMPILER(); ?>" string(200) "getStub()); + var_dump(strlen($p->getStub())); $p->setStub(" --EXPECT-- -string(29) " -" +int(4461) string(200) " +--FILE-- + +===DONE=== +--EXPECT-- +in b +