]> granicus.if.org Git - php/commitdiff
major improvement:
authorGreg Beaver <cellog@php.net>
Fri, 18 Jan 2008 05:42:16 +0000 (05:42 +0000)
committerGreg Beaver <cellog@php.net>
Fri, 18 Jan 2008 05:42:16 +0000 (05:42 +0000)
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

12 files changed:
ext/phar/makestub.php [new file with mode: 0644]
ext/phar/phar.c
ext/phar/phar_internal.h
ext/phar/shortarc.php [new file with mode: 0644]
ext/phar/stream.c
ext/phar/stub.h [new file with mode: 0644]
ext/phar/tests/nophar.phar [new file with mode: 0644]
ext/phar/tests/nophar.phar.inc [new file with mode: 0644]
ext/phar/tests/nophar.phpt [new file with mode: 0644]
ext/phar/tests/phar_commitwrite.phpt
ext/phar/tests/phar_create_in_cwd.phpt
ext/phar/tests/withphar.phpt [new file with mode: 0644]

diff --git a/ext/phar/makestub.php b/ext/phar/makestub.php
new file mode 100644 (file)
index 0000000..4296cab
--- /dev/null
@@ -0,0 +1,51 @@
+<?php
+$s = str_replace("\r", '', file_get_contents(dirname(__FILE__) . '/shortarc.php'));
+$s .= "\nExtract_Phar::go(XXXX);\n__HALT_COMPILER();";
+$news = '';
+$last = -1;
+foreach (token_get_all($s) as $token) {
+    if (is_array($token)) {
+        if ($token[0] == T_WHITESPACE) {
+            if ($last == T_COMMENT) {
+                $token[1] = '';
+            } else {
+                $n = str_repeat("\n", substr_count($token[1], "\n"));
+                $token[1] = strlen($n) ? $n : ' ';
+            }
+        }
+        $last = $token[0];
+        $news .= $token[1];
+    } else {
+        $news .= $token;
+    }
+}
+$s = $news . ' ?>';
+$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 <cellog@php.net>                             |
+  +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+static const char newstub[] = "' . $s . '";
+';
+
+file_put_contents(dirname(__FILE__) . '/stub.h', $stub);
+?>
\ No newline at end of file
index 92c63dd5d6e072a11e498ecf0b5b9ea46285bf31..38f3f75bc115050bc6393297391af2cf8d47ffe4 100644 (file)
@@ -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[] = "<?php __HALT_COMPILER(); ?>\r\n";
+#include "stub.h"
+/*     static const char newstub[] = "<?php __HALT_COMPILER(); ?>\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;
index 4fc713ae46c17dce00ee344e358194c4701bd568..82a60d9674bfb3e5e91c04161af1ce454e9bd173 100755 (executable)
@@ -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 (file)
index 0000000..5ab5757
--- /dev/null
@@ -0,0 +1,176 @@
+<?php
+if (in_array('phar', stream_get_wrappers()) && class_exists('Phar', 0)) {
+    Phar::interceptFileFuncs();
+    include 'phar://' . __FILE__ . '/index.php';
+    return;
+}
+class Extract_Phar
+{
+    static $tmp = array();
+    static $origdir;
+    const GZ = 0x1000;
+    const BZ2 = 0x2000;
+    const MASK = 0x3000;
+    static function go($D)
+    {
+        register_shutdown_function(array('Extract_Phar', '_removeTmpFiles'));
+        $fp = fopen(__FILE__, 'rb');
+        fseek($fp, $D);
+        $L = unpack('V', 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';
+        if (!file_exists($temp)) {
+            @mkdir($temp);
+            $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);
+            } 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
index ef0bdf0f5ba60281078fcb22926f4f1225d56fc2..cf24b5045d0ad2fd5220403a26280b1033298c61 100644 (file)
@@ -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 (file)
index 0000000..7f42a99
--- /dev/null
@@ -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 <cellog@php.net>                             |
+  +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+static const char newstub[] = "<?php\nif (in_array('phar', stream_get_wrappers()) && class_exists('Phar', 0)) {\nPhar::interceptFileFuncs();\ninclude 'phar://' . __FILE__ . '/index.php';\nreturn;\n}\nclass Extract_Phar\n{\nstatic $tmp = array();\nstatic $origdir;\nconst GZ = 0x1000;\nconst BZ2 = 0x2000;\nconst MASK = 0x3000;\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 '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 (file)
index 0000000..e3235b2
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 (file)
index 0000000..78867f1
--- /dev/null
@@ -0,0 +1,8 @@
+<?php
+$fname = dirname(__FILE__) . '/nophar.phar';
+@unlink($fname);
+$p = new Phar($fname);
+$p['index.php'] = '<?php include "b/c.php";' . "\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";
+?>
\ No newline at end of file
diff --git a/ext/phar/tests/nophar.phpt b/ext/phar/tests/nophar.phpt
new file mode 100644 (file)
index 0000000..2b7af7a
--- /dev/null
@@ -0,0 +1,14 @@
+--TEST--
+Phar: phar run without pecl/phar with default stub
+--SKIPIF--
+<?php if (extension_loaded("phar")) die("skip"); ?>
+--FILE--
+<?php
+include dirname(__FILE__) . '/nophar.phar';
+?>
+===DONE===
+--EXPECT--
+in b
+<?php include "b/c.php";
+in d
+===DONE===
index 8a68e8e5c64c5a327cc1b75f92cfad1a97ba70b6..b1ad5cffdafbed336169c891be2adee1fdc18abc 100644 (file)
@@ -26,10 +26,187 @@ var_dump($p->getStub());
 --CLEAN--
 <?php 
 unlink(dirname(__FILE__) . '/brandnewphar.phar');
+__HALT_COMPILER();
 ?>
 --EXPECT--
-string(29) "<?php __HALT_COMPILER(); ?>
-"
+string(4461) "<?php
+if (in_array('phar', stream_get_wrappers()) && class_exists('Phar', 0)) {
+Phar::interceptFileFuncs();
+include 'phar://' . __FILE__ . '/index.php';
+return;
+}
+class Extract_Phar
+{
+static $tmp = array();
+static $origdir;
+const GZ = 0x1000;
+const BZ2 = 0x2000;
+const MASK = 0x3000;
+static function go($D)
+{
+register_shutdown_function(array('Extract_Phar', '_removeTmpFiles'));
+$fp = fopen(__FILE__, 'rb');
+fseek($fp, $D);
+$L = unpack('V', 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';
+if (!file_exists($temp)) {
+@mkdir($temp);
+$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);
+} 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) "<?php
 function __autoload($class)
 {
index 630825481031af3ade02e4cdb203da296c6aa705..86a211df1dc9cdc29af16bab8159f8ca75434a2a 100644 (file)
@@ -11,7 +11,7 @@ chdir(dirname(__FILE__));
 try {
        $p = new Phar('brandnewphar.phar');
        $p['file1.txt'] = 'hi';
-       var_dump($p->getStub());
+       var_dump(strlen($p->getStub()));
        $p->setStub("<?php
 function __autoload(\$class)
 {
@@ -32,8 +32,7 @@ __HALT_COMPILER();
 unlink(dirname(__FILE__) . '/brandnewphar.phar');
 ?>
 --EXPECT--
-string(29) "<?php __HALT_COMPILER(); ?>
-"
+int(4461)
 string(200) "<?php
 function __autoload($class)
 {
diff --git a/ext/phar/tests/withphar.phpt b/ext/phar/tests/withphar.phpt
new file mode 100644 (file)
index 0000000..b4c95e8
--- /dev/null
@@ -0,0 +1,14 @@
+--TEST--
+Phar: phar run with pecl/phar with default stub
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--FILE--
+<?php
+include dirname(__FILE__) . '/nophar.phar';
+?>
+===DONE===
+--EXPECT--
+in b
+<?php include "b/c.php";
+in d
+===DONE===