[ --enable-phar Enable phar support, use --with-zlib-dir if zlib detection fails])
if test "$PHP_PHAR" != "no"; then
- PHP_NEW_EXTENSION(phar, phar.c phar_object.c, $ext_shared)
+ PHP_NEW_EXTENSION(phar, phar.c phar_object.c phar_path_check.c, $ext_shared)
PHP_ADD_EXTENSION_DEP(phar, zlib, true)
PHP_ADD_EXTENSION_DEP(phar, bz2, true)
PHP_ADD_EXTENSION_DEP(phar, spl, false)
ARG_ENABLE("phar", "enable phar support", "no");
if (PHP_PHAR != "no") {
- EXTENSION("phar", "phar.c phar_object.c");
+ EXTENSION("phar", "phar.c phar_object.c phar_path_check.c");
ADD_EXTENSION_DEP('phar', 'zlib', true);
ADD_EXTENSION_DEP('phar', 'bz2', true);
ADD_EXTENSION_DEP('phar', 'spl', false);
<file name="create_new_phar.phpt" role="test"/>
<file name="create_new_phar_b.phpt" role="test"/>
<file name="create_new_phar_c.phpt" role="test"/>
+ <file name="create_path_error.phpt" role="test"/>
<file name="delete_in_phar.phpt" role="test"/>
<file name="delete_in_phar_b.phpt" role="test"/>
<file name="delete_in_phar_confirm.phpt" role="test"/>
<file name="phar_object.c" role="src"/>
<file name="php_phar.h" role="src"/>
<file name="phar_internal.h" role="src"/>
+ <file name="phar_path_check.c" role="src"/>
+ <file name="phar_path_check.re" role="src"/>
</dir> <!-- / -->
</contents>
<dependencies>
phar_archive_data *phar;
phar_entry_info *entry, etemp;
phar_entry_data *ret;
+ phar_path_check_result res;
+ const char *pcr_error;
+
+ if ((res = phar_path_check(path, &path_len, &pcr_error)) > pcr_is_ok) {
+ if (error) {
+ spprintf(error, 0, "phar error: invalid path \"%s\" contains %s", path, pcr_error);
+ }
+ return NULL;
+ }
if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, error TSRMLS_CC)) {
return NULL;
if (FAILURE == phar_get_entry_data(&ret, fname, fname_len, path, path_len, mode, error TSRMLS_CC)) {
return NULL;
- }
- if (ret) {
+ } else if (ret) {
return ret;
}
if (error) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, error);
efree(error);
+ } else {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: file \"%s\" could not be created in phar \"%s\"", internal_file, resource->host);
}
- php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: file \"%s\" could not be created in phar \"%s\"", internal_file, resource->host);
efree(internal_file);
php_url_free(resource);
return NULL;
int phar_flush(phar_archive_data *archive, char *user_stub, long len, char **error TSRMLS_DC);
int phar_split_fname(char *filename, int filename_len, char **arch, int *arch_len, char **entry, int *entry_len TSRMLS_DC);
+typedef enum {
+ pcr_use_query,
+ pcr_is_ok,
+ pcr_err_double_slash,
+ pcr_err_up_dir,
+ pcr_err_curr_dir,
+ pcr_err_back_slash,
+ pcr_err_empty_entry
+} phar_path_check_result;
+
+phar_path_check_result phar_path_check(const char *p, int *len, const char **error);
+
END_EXTERN_C()
/*
--- /dev/null
+/* Generated by re2c 0.11.0 on Sun Feb 4 07:53:57 2007 */
+#line 1 "ext/phar/phar_path_check.re"
+/*
+ +----------------------------------------------------------------------+
+ | phar php single-file executable PHP extension |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2005-2006 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: Marcus Boerger <helly@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#include "phar_internal.h"
+
+phar_path_check_result phar_path_check(const char *s, int *len, const char **error)
+{
+ const unsigned char *p = (const unsigned char*)s;
+ const unsigned char *m;
+#define YYCTYPE unsigned char
+#define YYCURSOR p
+#define YYLIMIT p+*len
+#define YYMARKER m
+#define YYFILL(n)
+
+loop:
+{
+
+#line 39 "/usr/src/PHP_5_2/ext/phar/phar_path_check.c"
+ {
+ YYCTYPE yych;
+
+ if((YYLIMIT - YYCURSOR) < 4) YYFILL(4);
+ yych = *YYCURSOR;
+ if(yych <= '/') {
+ if(yych <= 0x09) {
+ if(yych <= 0x00) goto yy9;
+ goto yy11;
+ } else {
+ if(yych <= 0x0A) goto yy2;
+ if(yych <= '.') goto yy11;
+ goto yy3;
+ }
+ } else {
+ if(yych <= '?') {
+ if(yych <= '>') goto yy11;
+ goto yy7;
+ } else {
+ if(yych == '\\') goto yy5;
+ goto yy11;
+ }
+ }
+yy2:
+ YYCURSOR = YYMARKER;
+ goto yy4;
+yy3:
+ yych = *(YYMARKER = ++YYCURSOR);
+ if(yych <= 0x00) goto yy12;
+ if(yych <= '-') goto yy4;
+ if(yych <= '.') goto yy14;
+ if(yych <= '/') goto yy15;
+yy4:
+#line 73 "ext/phar/phar_path_check.re"
+ {
+ goto loop;
+ }
+#line 77 "/usr/src/PHP_5_2/ext/phar/phar_path_check.c"
+yy5:
+ ++YYCURSOR;
+#line 50 "ext/phar/phar_path_check.re"
+ {
+ *error = "back-slash";
+ return pcr_err_back_slash;
+ }
+#line 85 "/usr/src/PHP_5_2/ext/phar/phar_path_check.c"
+yy7:
+ ++YYCURSOR;
+#line 58 "ext/phar/phar_path_check.re"
+ {
+ if (*s == '/') {
+ s++;
+ }
+ *len = (p - (const unsigned char*)s) -1;
+ *error = NULL;
+ return pcr_use_query;
+ }
+#line 97 "/usr/src/PHP_5_2/ext/phar/phar_path_check.c"
+yy9:
+ ++YYCURSOR;
+#line 66 "ext/phar/phar_path_check.re"
+ {
+ if (*s == '/') {
+ s++;
+ }
+ *error = NULL;
+ return pcr_is_ok;
+ }
+#line 108 "/usr/src/PHP_5_2/ext/phar/phar_path_check.c"
+yy11:
+ yych = *++YYCURSOR;
+ goto yy4;
+yy12:
+ ++YYCURSOR;
+#line 54 "ext/phar/phar_path_check.re"
+ {
+ *error = "empty entry";
+ return pcr_err_empty_entry;
+ }
+#line 119 "/usr/src/PHP_5_2/ext/phar/phar_path_check.c"
+yy14:
+ yych = *++YYCURSOR;
+ if(yych <= 0x00) goto yy18;
+ if(yych <= '-') goto yy2;
+ if(yych <= '.') goto yy17;
+ if(yych <= '/') goto yy18;
+ goto yy2;
+yy15:
+ ++YYCURSOR;
+#line 38 "ext/phar/phar_path_check.re"
+ {
+ *error = "double slash";
+ return pcr_err_double_slash;
+ }
+#line 134 "/usr/src/PHP_5_2/ext/phar/phar_path_check.c"
+yy17:
+ yych = *++YYCURSOR;
+ if(yych <= 0x00) goto yy20;
+ if(yych == '/') goto yy20;
+ goto yy2;
+yy18:
+ ++YYCURSOR;
+#line 46 "ext/phar/phar_path_check.re"
+ {
+ *error = "current directory reference";
+ return pcr_err_curr_dir;
+ }
+#line 147 "/usr/src/PHP_5_2/ext/phar/phar_path_check.c"
+yy20:
+ ++YYCURSOR;
+#line 42 "ext/phar/phar_path_check.re"
+ {
+ *error = "upper directory reference";
+ return pcr_err_up_dir;
+ }
+#line 155 "/usr/src/PHP_5_2/ext/phar/phar_path_check.c"
+ }
+}
+#line 76 "ext/phar/phar_path_check.re"
+
+}
--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | phar php single-file executable PHP extension |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2005-2006 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: Marcus Boerger <helly@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#include "phar_internal.h"
+
+phar_path_check_result phar_path_check(const char *s, int *len, const char **error)
+{
+ const unsigned char *p = (const unsigned char*)s;
+ const unsigned char *m;
+#define YYCTYPE unsigned char
+#define YYCURSOR p
+#define YYLIMIT p+*len
+#define YYMARKER m
+#define YYFILL(n)
+
+loop:
+/*!re2c
+END = "\x00";
+EOS = "/" | END;
+ANY = .;
+"//" {
+ *error = "double slash";
+ return pcr_err_double_slash;
+ }
+"/.." EOS {
+ *error = "upper directory reference";
+ return pcr_err_up_dir;
+ }
+"/." EOS {
+ *error = "current directory reference";
+ return pcr_err_curr_dir;
+ }
+"\\" {
+ *error = "back-slash";
+ return pcr_err_back_slash;
+ }
+"/" END {
+ *error = "empty entry";
+ return pcr_err_empty_entry;
+ }
+"?" {
+ if (*s == '/') {
+ s++;
+ }
+ *len = (p - (const unsigned char*)s) -1;
+ *error = NULL;
+ return pcr_use_query;
+ }
+END {
+ if (*s == '/') {
+ s++;
+ }
+ *error = NULL;
+ return pcr_is_ok;
+ }
+ANY {
+ goto loop;
+ }
+*/
+}
--- /dev/null
+--TEST--
+Phar: create with illegal path
+--SKIPIF--
+<?php if (!extension_loaded("phar")) print "skip"; ?>
+<?php if (!extension_loaded("spl")) print "skip SPL not available"; ?>
+--INI--
+phar.readonly=0
+phar.require_hash=1
+--FILE--
+<?php
+
+$fname = dirname(__FILE__) . '/' . basename(__FILE__, '.php') . '.phar.php';
+$pname = 'phar://' . $fname;
+
+@unlink($fname);
+
+file_put_contents($pname . '/a.php?', "query");
+file_put_contents($pname . '/b.php?bla', "query");
+
+var_dump(file_get_contents($pname . '/a.php'));
+var_dump(file_get_contents($pname . '/b.php'));
+
+function error_handler($errno, $errmsg)
+{
+ echo "Error: $errmsg\n";
+}
+
+set_error_handler('error_handler');
+
+$checks = array('//', '/.', '/../', '/a/..');
+foreach($checks as $check)
+{
+ file_put_contents($pname . $check, "error");
+}
+
+?>
+===DONE===
+--CLEAN--
+<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
+--EXPECTF--
+string(5) "query"
+string(5) "query"
+Error: file_put_contents(phar://%s//): failed to open stream: phar error: invalid path "/" contains empty entry
+Error: file_put_contents(phar://%s/../): failed to open stream: phar error: invalid path "../" contains empty entry
+Error: file_put_contents(phar://%s/a/..): failed to open stream: phar error: invalid path "a/.." contains upper directory reference
+===DONE===