2005-12-05 04:35:38 +08:00
/*
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2005-12-05 06:50:54 +08:00
| phar php single - file executable PHP extension |
2005-12-05 04:35:38 +08:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2006-01-24 03:30:14 +08:00
| Copyright ( c ) 2005 - 2006 The PHP Group |
2005-12-05 04:35:38 +08:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2005-12-05 06:50:54 +08:00
| This source file is subject to version 3.01 of the PHP license , |
2005-12-05 04:35:38 +08:00
| that is bundled with this package in the file LICENSE , and is |
| available through the world - wide - web at the following url : |
2005-12-05 06:50:54 +08:00
| http : //www.php.net/license/3_01.txt. |
2005-12-05 04:35:38 +08:00
| 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 . |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2006-01-04 21:18:31 +08:00
| Authors : Gregory Beaver < cellog @ php . net > |
| Marcus Boerger < helly @ php . net > |
2005-12-05 04:35:38 +08:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
*/
/* $Id$ */
# ifdef HAVE_CONFIG_H
# include "config.h"
# endif
# include <time.h>
# include "php.h"
# include "php_ini.h"
# include "ext/standard/info.h"
# include "ext/standard/url.h"
# include "ext/standard/crc32.h"
2006-02-28 09:36:30 +08:00
# include "ext/spl/spl_array.h"
# include "ext/spl/spl_directory.h"
2006-03-05 06:48:05 +08:00
# include "ext/spl/spl_engine.h"
2006-02-28 09:36:30 +08:00
# include "ext/spl/spl_exceptions.h"
2005-12-05 04:35:38 +08:00
# include "zend_constants.h"
2006-02-28 09:36:30 +08:00
# include "zend_execute.h"
# include "zend_exceptions.h"
# include "zend_hash.h"
# include "zend_interfaces.h"
2006-01-02 04:16:09 +08:00
# include "zend_operators.h"
2006-02-28 09:36:30 +08:00
# include "zend_qsort.h"
2005-12-05 04:35:38 +08:00
# include "php_phar.h"
2005-12-05 12:47:29 +08:00
# include "main/php_streams.h"
2006-02-28 09:36:30 +08:00
# ifdef HAVE_STDINT_H
# include <stdint.h>
# endif
2006-01-10 14:46:17 +08:00
2005-12-05 04:35:38 +08:00
# ifndef TRUE
# define TRUE 1
# define FALSE 0
# endif
2006-01-10 14:46:17 +08:00
# ifndef E_RECOVERABLE_ERROR
# define E_RECOVERABLE_ERROR E_ERROR
# endif
2006-01-13 05:16:29 +08:00
# define PHAR_VERSION_STR "0.8.0"
2006-01-10 14:46:17 +08:00
/* x.y.z maps to 0xyz0 */
2006-01-13 05:16:29 +08:00
# define PHAR_API_VERSION 0x0800
# define PHAR_API_MAJORVERSION 0x0000
# define PHAR_API_MAJORVER_MASK 0xF000
# define PHAR_API_VER_MASK 0xFFF0
# define PHAR_HDR_ANY_COMPRESSED 0x0001
# define PHAR_HDR_SIGNATURE 0x0008
2006-01-10 14:46:17 +08:00
/* flags byte for each file adheres to these bitmasks.
All unused values are reserved */
2006-01-13 05:16:29 +08:00
# define PHAR_ENT_COMPRESSION_MASK 0x0F
# define PHAR_ENT_COMPRESSED_NONE 0x00
# define PHAR_ENT_COMPRESSED_GZ 0x01
# define PHAR_ENT_COMPRESSED_BZ2 0x02
2006-01-10 14:46:17 +08:00
ZEND_BEGIN_MODULE_GLOBALS ( phar )
2006-02-28 09:36:30 +08:00
HashTable phar_fname_map ;
2006-01-12 05:19:46 +08:00
HashTable phar_alias_map ;
2006-01-10 14:46:17 +08:00
ZEND_END_MODULE_GLOBALS ( phar )
2005-12-05 04:35:38 +08:00
ZEND_DECLARE_MODULE_GLOBALS ( phar )
2006-01-10 14:46:17 +08:00
# ifndef php_uint16
# if SIZEOF_SHORT == 2
# define php_uint16 unsigned short
# else
2006-02-28 09:36:30 +08:00
# define php_uint16 uint16_t
2006-01-10 14:46:17 +08:00
# endif
# endif
2006-03-04 10:12:22 +08:00
typedef union _phar_archive_object phar_archive_object ;
2006-03-08 08:56:31 +08:00
typedef union _phar_entry_object phar_entry_object ;
2006-02-28 09:36:30 +08:00
2006-01-04 23:50:45 +08:00
/* entry for one file in a phar file */
typedef struct _phar_manifest_entry {
2006-02-28 09:36:30 +08:00
php_uint32 filename_len ;
char * filename ;
php_uint32 uncompressed_filesize ;
php_uint32 timestamp ;
long offset_within_phar ;
php_uint32 compressed_filesize ;
php_uint32 crc32 ;
char flags ;
zend_bool crc_checked ;
php_stream * fp ;
} phar_entry_info ;
2006-03-04 10:12:22 +08:00
/* information about a phar file (the archive itself) */
typedef struct _phar_archive_data {
2006-02-28 09:36:30 +08:00
char * fname ;
int fname_len ;
char * alias ;
int alias_len ;
char version [ 12 ] ;
size_t internal_file_start ;
zend_bool has_compressed_files ;
HashTable manifest ;
2006-03-03 06:44:39 +08:00
php_uint32 min_timestamp ;
php_uint32 max_timestamp ;
2006-02-28 09:36:30 +08:00
php_stream * fp ;
2006-03-08 08:56:31 +08:00
int refcount ;
2006-03-04 10:12:22 +08:00
} phar_archive_data ;
2006-01-04 23:50:45 +08:00
/* stream access data for one file entry in a phar file */
2006-02-28 09:36:30 +08:00
typedef struct _phar_entry_data {
2006-03-08 08:56:31 +08:00
phar_archive_data * phar ;
2006-02-28 09:36:30 +08:00
php_stream * fp ;
2006-03-03 06:44:39 +08:00
phar_entry_info * internal_file ;
2006-02-28 09:36:30 +08:00
} phar_entry_data ;
2006-03-04 10:12:22 +08:00
/* archive php object */
union _phar_archive_object {
2006-02-28 09:36:30 +08:00
zend_object std ;
spl_filesystem_object spl ;
struct {
zend_object std ;
2006-03-08 08:56:31 +08:00
phar_archive_data * archive ;
2006-02-28 09:36:30 +08:00
} arc ;
} ;
/* entry php object */
union _phar_entry_object {
zend_object std ;
spl_filesystem_object spl ;
struct {
zend_object std ;
phar_entry_info * entry ;
} ent ;
} ;
2005-12-05 04:35:38 +08:00
2006-01-04 23:50:45 +08:00
/* {{{ forward declarations */
static php_stream * php_stream_phar_url_wrapper ( php_stream_wrapper * wrapper , char * path , char * mode , int options , char * * opened_path , php_stream_context * context STREAMS_DC TSRMLS_DC ) ;
static int phar_close ( php_stream * stream , int close_handle TSRMLS_DC ) ;
static int phar_closedir ( php_stream * stream , int close_handle TSRMLS_DC ) ;
static int phar_seekdir ( php_stream * stream , off_t offset , int whence , off_t * newoffset TSRMLS_DC ) ;
static size_t phar_read ( php_stream * stream , char * buf , size_t count TSRMLS_DC ) ;
static size_t phar_readdir ( php_stream * stream , char * buf , size_t count TSRMLS_DC ) ;
static int phar_seek ( php_stream * stream , off_t offset , int whence , off_t * newoffset TSRMLS_DC ) ;
static size_t phar_write ( php_stream * stream , const char * buf , size_t count TSRMLS_DC ) ;
static int phar_flush ( php_stream * stream TSRMLS_DC ) ;
static int phar_stat ( php_stream * stream , php_stream_statbuf * ssb TSRMLS_DC ) ;
static int phar_stream_stat ( php_stream_wrapper * wrapper , char * url , int flags , php_stream_statbuf * ssb , php_stream_context * context TSRMLS_DC ) ;
static php_stream * phar_opendir ( php_stream_wrapper * wrapper , char * filename , char * mode ,
int options , char * * opened_path , php_stream_context * context STREAMS_DC TSRMLS_DC ) ;
/* }}} */
2006-03-04 10:12:22 +08:00
static zend_class_entry * phar_ce_archive ;
2006-02-28 09:36:30 +08:00
static zend_class_entry * phar_ce_entry ;
2005-12-05 04:35:38 +08:00
2006-03-08 08:56:31 +08:00
static void phar_destroy_phar_data ( phar_archive_data * data TSRMLS_DC ) /* { { { */
2005-12-05 04:35:38 +08:00
{
2006-01-12 05:19:46 +08:00
if ( data - > alias & & data - > alias ! = data - > fname ) {
efree ( data - > alias ) ;
2006-02-28 09:36:30 +08:00
data - > alias = NULL ;
2006-01-12 05:19:46 +08:00
}
efree ( data - > fname ) ;
2006-01-05 19:32:05 +08:00
zend_hash_destroy ( & data - > manifest ) ;
2006-01-10 14:46:17 +08:00
if ( data - > fp ) {
php_stream_close ( data - > fp ) ;
}
data - > fp = 0 ;
2006-03-09 04:07:25 +08:00
efree ( data ) ;
2005-12-05 04:35:38 +08:00
}
2006-01-04 23:50:45 +08:00
/* }}}*/
2005-12-05 04:35:38 +08:00
2006-03-08 08:56:31 +08:00
static void destroy_phar_data ( void * pDest ) /* { { { */
{
2006-03-09 04:07:25 +08:00
phar_archive_data * phar_data = * ( phar_archive_data * * ) pDest ;
2006-03-08 08:56:31 +08:00
TSRMLS_FETCH ( ) ;
2006-03-09 04:07:25 +08:00
if ( - - phar_data - > refcount < 0 ) {
phar_destroy_phar_data ( phar_data TSRMLS_CC ) ;
}
2006-03-08 08:56:31 +08:00
}
/* }}}*/
2006-03-09 04:07:25 +08:00
static void phar_spl_foreign_dtor ( spl_filesystem_object * object TSRMLS_DC ) /* { { { */
{
phar_archive_data * phar_data = ( phar_archive_data * ) object - > oth ;
if ( - - phar_data - > refcount < 0 ) {
phar_destroy_phar_data ( phar_data TSRMLS_CC ) ;
}
}
/* }}} */
2006-03-09 04:31:23 +08:00
static void phar_spl_foreign_clone ( spl_filesystem_object * src , spl_filesystem_object * dst TSRMLS_DC ) /* { { { */
{
phar_archive_data * phar_data = ( phar_archive_data * ) dst - > oth ;
phar_data - > refcount + + ;
}
/* }}} */
static spl_other_handler phar_spl_foreign_handler = {
phar_spl_foreign_dtor ,
2006-03-11 07:53:41 +08:00
phar_spl_foreign_clone
2006-03-09 04:31:23 +08:00
} ;
2006-01-04 23:50:45 +08:00
static void destroy_phar_manifest ( void * pDest ) /* { { { */
2005-12-05 04:35:38 +08:00
{
2006-02-28 09:36:30 +08:00
phar_entry_info * entry = ( phar_entry_info * ) pDest ;
2006-01-04 23:27:18 +08:00
2006-01-10 14:46:17 +08:00
if ( entry - > fp ) {
2006-01-11 08:50:07 +08:00
TSRMLS_FETCH ( ) ;
2006-01-10 14:46:17 +08:00
php_stream_close ( entry - > fp ) ;
}
entry - > fp = 0 ;
2006-01-04 23:27:18 +08:00
efree ( entry - > filename ) ;
2005-12-05 04:35:38 +08:00
}
2006-01-04 23:50:45 +08:00
/* }}} */
2005-12-05 04:35:38 +08:00
2006-03-04 10:12:22 +08:00
static phar_archive_data * phar_get_archive ( char * fname , int fname_len , char * alias , int alias_len TSRMLS_DC ) /* { { { */
2005-12-05 04:35:38 +08:00
{
2006-03-04 10:12:22 +08:00
phar_archive_data * fd , * * fd_ptr ;
2006-01-11 09:51:47 +08:00
if ( alias & & alias_len ) {
2006-01-12 05:19:46 +08:00
if ( SUCCESS = = zend_hash_find ( & ( PHAR_GLOBALS - > phar_alias_map ) , alias , alias_len , ( void * * ) & fd_ptr ) ) {
if ( fname & & ( fname_len ! = ( * fd_ptr ) - > fname_len | | strncmp ( fname , ( * fd_ptr ) - > fname , fname_len ) ) ) {
php_error_docref ( NULL TSRMLS_CC , E_RECOVERABLE_ERROR , " alias \" %s \" is already used for archive \" %s \" cannot be overloaded with \" %s \" " , alias , ( * fd_ptr ) - > fname , fname ) ;
return NULL ;
}
return * fd_ptr ;
2006-01-11 09:51:47 +08:00
}
}
if ( fname & & fname_len ) {
2006-03-09 04:07:25 +08:00
if ( SUCCESS = = zend_hash_find ( & ( PHAR_GLOBALS - > phar_fname_map ) , fname , fname_len , ( void * * ) & fd_ptr ) ) {
fd = * fd_ptr ;
2006-01-12 05:19:46 +08:00
if ( alias & & alias_len ) {
2006-03-04 10:12:22 +08:00
zend_hash_add ( & ( PHAR_GLOBALS - > phar_alias_map ) , alias , alias_len , ( void * ) & fd , sizeof ( phar_archive_data * ) , NULL ) ;
2006-01-12 05:19:46 +08:00
}
2006-01-11 09:51:47 +08:00
return fd ;
}
2006-01-12 05:19:46 +08:00
if ( SUCCESS = = zend_hash_find ( & ( PHAR_GLOBALS - > phar_alias_map ) , fname , fname_len , ( void * * ) & fd_ptr ) ) {
return * fd_ptr ;
2006-01-11 09:51:47 +08:00
}
}
return NULL ;
}
/* }}} */
2006-03-04 10:12:22 +08:00
static phar_entry_info * phar_get_entry_info ( phar_archive_data * phar , char * path , int path_len TSRMLS_DC ) /* { { { */
2006-02-28 09:36:30 +08:00
{
phar_entry_info * entry ;
if ( path & & * path = = ' / ' ) {
path + + ;
path_len - - ;
}
if ( SUCCESS = = zend_hash_find ( & phar - > manifest , path , path_len , ( void * * ) & entry ) ) {
return entry ;
}
return NULL ;
}
/* }}} */
static phar_entry_data * phar_get_entry_data ( char * fname , int fname_len , char * path , int path_len TSRMLS_DC ) /* { { { */
2006-01-11 09:51:47 +08:00
{
2006-03-04 10:12:22 +08:00
phar_archive_data * phar ;
2006-02-28 09:36:30 +08:00
phar_entry_info * entry ;
phar_entry_data * ret ;
2005-12-05 04:35:38 +08:00
ret = NULL ;
2006-03-04 10:12:22 +08:00
if ( ( phar = phar_get_archive ( fname , fname_len , NULL , 0 TSRMLS_CC ) ) ! = NULL ) {
2006-02-28 09:36:30 +08:00
if ( ( entry = phar_get_entry_info ( phar , path , path_len TSRMLS_CC ) ) ! = NULL ) {
ret = ( phar_entry_data * ) emalloc ( sizeof ( phar_entry_data ) ) ;
2006-01-11 09:51:47 +08:00
ret - > phar = phar ;
ret - > internal_file = entry ;
if ( entry - > fp ) {
2006-01-06 06:24:41 +08:00
/* transfer ownership */
2006-01-11 09:51:47 +08:00
ret - > fp = entry - > fp ;
2006-01-07 01:23:42 +08:00
php_stream_seek ( ret - > fp , 0 , SEEK_SET ) ;
2006-01-11 09:51:47 +08:00
entry - > fp = 0 ;
2006-01-06 06:24:41 +08:00
} else {
ret - > fp = 0 ;
}
2005-12-05 04:35:38 +08:00
}
}
return ret ;
}
2006-01-04 23:50:45 +08:00
/* }}} */
2005-12-05 04:35:38 +08:00
2006-01-03 23:50:46 +08:00
/* {{{ proto string apiVersion()
* Returns the api version */
PHP_METHOD ( Phar , apiVersion )
{
2006-01-13 05:16:29 +08:00
RETURN_STRINGL ( PHAR_VERSION_STR , sizeof ( PHAR_VERSION_STR ) - 1 , 1 ) ;
2006-01-03 23:50:46 +08:00
}
/* }}}*/
2005-12-05 04:35:38 +08:00
2006-01-03 23:50:46 +08:00
/* {{{ proto bool canCompress()
* Returns whether phar extension supports compression using zlib */
2006-01-02 06:49:10 +08:00
PHP_METHOD ( Phar , canCompress )
2005-12-07 14:39:03 +08:00
{
2006-01-13 05:16:29 +08:00
# if HAVE_ZLIB || HAVE_BZ2
2005-12-07 14:39:03 +08:00
RETURN_TRUE ;
# else
RETURN_FALSE ;
# endif
}
2006-01-03 23:50:46 +08:00
/* }}} */
2005-12-05 04:35:38 +08:00
2006-01-04 10:26:15 +08:00
# define MAPPHAR_ALLOC_FAIL(msg) \
php_stream_close ( fp ) ; \
2006-01-10 14:46:17 +08:00
php_error_docref ( NULL TSRMLS_CC , E_RECOVERABLE_ERROR , msg , fname ) ; \
2006-01-04 10:26:15 +08:00
return FAILURE ;
# define MAPPHAR_FAIL(msg) \
efree ( savebuf ) ; \
MAPPHAR_ALLOC_FAIL ( msg )
2006-01-05 08:39:31 +08:00
# ifdef WORDS_BIGENDIAN
2006-01-10 14:46:17 +08:00
# define PHAR_GET_32(buffer, var) \
var = ( ( unsigned char ) buffer [ 3 ] ) < < 24 \
+ ( ( unsigned char ) buffer [ 2 ] ) < < 16 \
+ ( ( unsigned char ) buffer [ 1 ] ) < < 8 \
2006-01-05 08:39:31 +08:00
+ ( ( unsigned char ) buffer [ 0 ] ) ; \
buffer + = 4
# else
2006-01-10 14:46:17 +08:00
# define PHAR_GET_32(buffer, var) \
2006-01-06 06:24:41 +08:00
var = * ( php_uint32 * ) ( buffer ) ; \
2006-01-05 08:39:31 +08:00
buffer + = 4
# endif
2006-03-04 10:12:22 +08:00
static int phar_open_file ( php_stream * fp , char * fname , int fname_len , char * alias , int alias_len , long halt_offset , phar_archive_data * * pphar TSRMLS_DC ) /* { { { */
2005-12-05 04:35:38 +08:00
{
2006-01-10 14:46:17 +08:00
char b32 [ 4 ] , * buffer , * endbuffer , * savebuf ;
2006-03-09 04:07:25 +08:00
phar_archive_data * mydata ;
2006-02-28 09:36:30 +08:00
phar_entry_info entry ;
2006-01-10 14:46:17 +08:00
php_uint32 manifest_len , manifest_count , manifest_index , tmp_len ;
php_uint16 manifest_tag ;
long offset ;
int compressed = 0 ;
2006-01-12 05:19:46 +08:00
int register_alias ;
2005-12-05 04:35:38 +08:00
2006-02-28 09:36:30 +08:00
if ( pphar ) {
* pphar = NULL ;
}
2006-03-09 04:07:25 +08:00
if ( ( mydata = phar_get_archive ( fname , fname_len , alias , alias_len TSRMLS_CC ) ) ! = NULL ) {
2006-01-07 03:20:21 +08:00
/* Overloading or reloading an archive would only be possible if we */
/* refcount everything to be sure no stream for any file in the */
/* archive is open. */
2006-03-09 04:07:25 +08:00
if ( fname_len ! = mydata - > fname_len | | strncmp ( fname , mydata - > fname , fname_len ) ) {
2006-01-07 03:20:21 +08:00
php_stream_close ( fp ) ;
2006-03-09 04:07:25 +08:00
php_error_docref ( NULL TSRMLS_CC , E_RECOVERABLE_ERROR , " alias \" %s \" is already used for archive \" %s \" cannot be overloaded with \" %s \" " , alias , mydata - > fname , fname ) ;
2006-01-10 14:46:17 +08:00
return FAILURE ;
2006-01-07 03:20:21 +08:00
} else {
2006-02-28 09:36:30 +08:00
if ( pphar ) {
2006-03-09 04:07:25 +08:00
* pphar = mydata ;
2006-02-28 09:36:30 +08:00
}
2006-01-07 03:20:21 +08:00
php_stream_close ( fp ) ;
return SUCCESS ;
}
}
2005-12-08 15:38:44 +08:00
/* check for ?>\n and increment accordingly */
2005-12-08 15:08:49 +08:00
if ( - 1 = = php_stream_seek ( fp , halt_offset , SEEK_SET ) ) {
2005-12-08 15:34:16 +08:00
MAPPHAR_ALLOC_FAIL ( " cannot seek to __HALT_COMPILER(); location in phar \" %s \" " )
2005-12-08 14:46:02 +08:00
}
2006-01-10 14:46:17 +08:00
buffer = b32 ;
2005-12-07 14:39:03 +08:00
if ( 3 ! = php_stream_read ( fp , buffer , 3 ) ) {
2006-01-10 14:46:17 +08:00
MAPPHAR_ALLOC_FAIL ( " internal corruption of phar \" %s \" (truncated manifest) " )
2005-12-05 04:35:38 +08:00
}
if ( * buffer = = ' ' & & * ( buffer + 1 ) = = ' ? ' & & * ( buffer + 2 ) = = ' > ' ) {
int nextchar ;
2005-12-07 09:18:54 +08:00
halt_offset + = 3 ;
2005-12-07 14:39:03 +08:00
if ( EOF = = ( nextchar = php_stream_getc ( fp ) ) ) {
2006-01-10 14:46:17 +08:00
MAPPHAR_ALLOC_FAIL ( " internal corruption of phar \" %s \" (truncated manifest) " )
2005-12-07 14:39:03 +08:00
}
2005-12-05 04:35:38 +08:00
if ( ( char ) nextchar = = ' \r ' ) {
2005-12-07 14:39:03 +08:00
if ( EOF = = ( nextchar = php_stream_getc ( fp ) ) ) {
2006-01-10 14:46:17 +08:00
MAPPHAR_ALLOC_FAIL ( " internal corruption of phar \" %s \" (truncated manifest) " )
2005-12-07 14:39:03 +08:00
}
2005-12-05 04:35:38 +08:00
halt_offset + + ;
}
if ( ( char ) nextchar = = ' \n ' ) {
halt_offset + + ;
}
}
2005-12-08 15:38:44 +08:00
/* make sure we are at the right location to read the manifest */
2005-12-08 15:08:49 +08:00
if ( - 1 = = php_stream_seek ( fp , halt_offset , SEEK_SET ) ) {
2006-01-10 14:46:17 +08:00
MAPPHAR_ALLOC_FAIL ( " cannot seek to __HALT_COMPILER(); location in phar \" %s \" " )
2005-12-08 15:08:49 +08:00
}
2005-12-05 04:35:38 +08:00
2005-12-08 15:38:44 +08:00
/* read in manifest */
2006-01-10 14:46:17 +08:00
buffer = b32 ;
2005-12-07 14:39:03 +08:00
if ( 4 ! = php_stream_read ( fp , buffer , 4 ) ) {
2006-01-10 14:46:17 +08:00
MAPPHAR_ALLOC_FAIL ( " internal corruption of phar \" %s \" (truncated manifest) " )
2005-12-07 14:39:03 +08:00
}
2006-01-10 14:46:17 +08:00
PHAR_GET_32 ( buffer , manifest_len ) ;
2005-12-08 15:34:16 +08:00
if ( manifest_len > 1048576 ) {
/* prevent serious memory issues by limiting manifest to at most 1 MB in length */
2006-01-10 14:46:17 +08:00
MAPPHAR_ALLOC_FAIL ( " manifest cannot be larger than 1 MB in phar \" %s \" " )
2005-12-07 14:39:03 +08:00
}
2006-01-10 14:46:17 +08:00
buffer = ( char * ) emalloc ( manifest_len ) ;
2005-12-05 04:35:38 +08:00
savebuf = buffer ;
endbuffer = buffer + manifest_len ;
2005-12-07 14:39:03 +08:00
if ( manifest_len ! = php_stream_read ( fp , buffer , manifest_len ) ) {
MAPPHAR_FAIL ( " internal corruption of phar \" %s \" (truncated manifest) " )
}
2006-01-11 08:50:07 +08:00
if ( manifest_len < 10 ) {
MAPPHAR_FAIL ( " internal corruption of phar \" %s \" (truncated manifest header) " )
}
2006-01-10 14:46:17 +08:00
2005-12-08 15:38:44 +08:00
/* extract the number of entries */
2006-01-10 14:46:17 +08:00
PHAR_GET_32 ( buffer , manifest_count ) ;
if ( manifest_count = = 0 ) {
MAPPHAR_FAIL ( " in phar \" %s \" , manifest claims to have zero entries. Phars must have at least 1 entry " ) ;
2006-01-05 08:39:31 +08:00
}
2006-01-10 14:46:17 +08:00
/* extract API version and global compressed flag */
manifest_tag = ( ( ( unsigned char ) buffer [ 0 ] ) < < 8 )
+ ( ( unsigned char ) buffer [ 1 ] ) ;
buffer + = 2 ;
if ( ( manifest_tag & PHAR_API_VER_MASK ) < PHAR_API_VERSION | |
( manifest_tag & PHAR_API_MAJORVER_MASK ) ! = PHAR_API_MAJORVERSION )
{
2006-02-28 09:36:30 +08:00
php_error_docref ( NULL TSRMLS_CC , E_RECOVERABLE_ERROR , " phar \" %s \" is API version %1.u.%1.u.%1.u, and cannot be processed " , fname , manifest_tag > > 12 , ( manifest_tag > > 8 ) & 0xF , ( manifest_tag > > 4 ) & 0x0F ) ;
2006-01-10 14:46:17 +08:00
efree ( savebuf ) ;
return FAILURE ;
}
2006-01-13 05:16:29 +08:00
/* The lowest nibble contains the phar wide flags. The any compressed can */
/* be ignored on reading because it is being generated anyways. */
2006-01-10 14:46:17 +08:00
/* extract alias */
PHAR_GET_32 ( buffer , tmp_len ) ;
2006-01-11 08:50:07 +08:00
if ( buffer + tmp_len > endbuffer ) {
2006-01-10 14:46:17 +08:00
MAPPHAR_FAIL ( " internal corruption of phar \" %s \" (buffer overrun) " ) ;
}
2006-01-11 08:50:07 +08:00
if ( manifest_len < 10 + tmp_len ) {
MAPPHAR_FAIL ( " internal corruption of phar \" %s \" (truncated manifest header) " )
}
/* tmp_len = 0 says alias length is 0, which means the alias is not stored in the phar */
2006-01-10 14:46:17 +08:00
if ( tmp_len ) {
/* if the alias is stored we enforce it (implicit overrides explicit) */
if ( alias & & alias_len & & ( alias_len ! = tmp_len | | strncmp ( alias , buffer , tmp_len ) ) )
{
buffer [ tmp_len ] = ' \0 ' ;
php_error_docref ( NULL TSRMLS_CC , E_RECOVERABLE_ERROR , " cannot load phar \" %s \" with implicit alias \" %s \" under different alias \" %s \" " , fname , buffer , alias ) ;
efree ( savebuf ) ;
return FAILURE ;
}
alias_len = tmp_len ;
alias = buffer ;
buffer + = tmp_len ;
2006-01-12 05:19:46 +08:00
register_alias = 1 ;
2006-01-10 14:46:17 +08:00
} else if ( ! alias_len | | ! alias ) {
/* if we neither have an explicit nor an implicit alias, we use the filename */
2006-01-12 05:19:46 +08:00
alias = NULL ;
alias_len = 0 ;
register_alias = 0 ;
} else {
register_alias = 1 ;
2006-01-10 14:46:17 +08:00
}
2006-01-11 08:50:07 +08:00
/* we have 5 32-bit items plus 1 byte at least */
if ( manifest_count > ( ( manifest_len - 10 - tmp_len ) / ( 5 * 4 + 1 ) ) ) {
/* prevent serious memory issues */
MAPPHAR_FAIL ( " internal corruption of phar \" %s \" (too many manifest entries for size of manifest) " )
}
2005-12-08 15:38:44 +08:00
/* set up our manifest */
2006-03-09 04:07:25 +08:00
mydata = emalloc ( sizeof ( phar_archive_data ) ) ;
zend_hash_init ( & mydata - > manifest , sizeof ( phar_entry_info ) ,
2005-12-05 04:35:38 +08:00
zend_get_hash_value , destroy_phar_manifest , 0 ) ;
2006-01-10 14:46:17 +08:00
offset = 0 ;
2006-03-09 04:07:25 +08:00
mydata - > min_timestamp = 0 ;
mydata - > max_timestamp = 0 ;
2005-12-05 04:35:38 +08:00
for ( manifest_index = 0 ; manifest_index < manifest_count ; manifest_index + + ) {
2006-01-05 08:39:31 +08:00
if ( buffer + 4 > endbuffer ) {
2006-01-11 08:50:07 +08:00
MAPPHAR_FAIL ( " internal corruption of phar \" %s \" (truncated manifest entry) " )
2005-12-07 14:39:03 +08:00
}
2006-01-10 14:46:17 +08:00
PHAR_GET_32 ( buffer , entry . filename_len ) ;
if ( entry . filename_len = = 0 ) {
MAPPHAR_FAIL ( " zero-length filename encountered in phar \" %s \" " ) ;
}
if ( buffer + entry . filename_len + 16 + 1 > endbuffer ) {
2006-01-11 08:50:07 +08:00
MAPPHAR_FAIL ( " internal corruption of phar \" %s \" (truncated manifest entry) " ) ;
2006-01-05 08:39:31 +08:00
}
2006-01-04 23:27:18 +08:00
entry . filename = estrndup ( buffer , entry . filename_len ) ;
2005-12-05 12:21:36 +08:00
buffer + = entry . filename_len ;
2006-01-10 14:46:17 +08:00
PHAR_GET_32 ( buffer , entry . uncompressed_filesize ) ;
PHAR_GET_32 ( buffer , entry . timestamp ) ;
2006-03-03 06:44:39 +08:00
if ( offset = = 0 ) {
2006-03-09 04:07:25 +08:00
mydata - > min_timestamp = entry . timestamp ;
mydata - > max_timestamp = entry . timestamp ;
2006-03-03 06:44:39 +08:00
} else {
2006-03-09 04:07:25 +08:00
if ( mydata - > min_timestamp > entry . timestamp ) {
mydata - > min_timestamp = entry . timestamp ;
} else if ( mydata - > max_timestamp < entry . timestamp ) {
mydata - > max_timestamp = entry . timestamp ;
2006-03-03 06:44:39 +08:00
}
}
2006-01-10 14:46:17 +08:00
PHAR_GET_32 ( buffer , entry . compressed_filesize ) ;
PHAR_GET_32 ( buffer , entry . crc32 ) ;
entry . offset_within_phar = offset ;
offset + = entry . compressed_filesize ;
entry . flags = * buffer + + ;
2006-01-13 05:16:29 +08:00
switch ( entry . flags & PHAR_ENT_COMPRESSION_MASK ) {
case PHAR_ENT_COMPRESSED_GZ :
2006-01-12 07:55:57 +08:00
# if !HAVE_ZLIB
2006-02-28 09:36:30 +08:00
MAPPHAR_FAIL ( " zlib extension is required for gz compressed .phar file \" %s \" " ) ;
2006-01-07 01:23:42 +08:00
# endif
2006-01-05 08:55:55 +08:00
compressed = 1 ;
2006-01-13 05:16:29 +08:00
break ;
case PHAR_ENT_COMPRESSED_BZ2 :
# if !HAVE_BZ2
2006-02-28 09:36:30 +08:00
MAPPHAR_FAIL ( " bz2 extension is required for bzip2 compressed .phar file \" %s \" " ) ;
2006-01-13 05:16:29 +08:00
# endif
compressed = 1 ;
break ;
default :
if ( entry . uncompressed_filesize ! = entry . compressed_filesize ) {
MAPPHAR_FAIL ( " internal corruption of phar \" %s \" (compressed and uncompressed size does not match for uncompressed entry) " ) ;
}
break ;
2006-01-06 06:24:41 +08:00
}
2005-12-10 08:00:00 +08:00
entry . crc_checked = 0 ;
2006-01-06 06:24:41 +08:00
entry . fp = NULL ;
2006-03-09 04:07:25 +08:00
zend_hash_add ( & mydata - > manifest , entry . filename , entry . filename_len , ( void * ) & entry , sizeof ( phar_entry_info ) , NULL ) ;
}
mydata - > fname = estrndup ( fname , fname_len ) ;
mydata - > fname_len = fname_len ;
mydata - > alias = alias ? estrndup ( alias , alias_len ) : mydata - > fname ;
mydata - > alias_len = alias ? alias_len : fname_len ;
snprintf ( mydata - > version , sizeof ( mydata - > version ) , " %u.%u.%u " , manifest_tag > > 12 , ( manifest_tag > > 8 ) & 0xF , ( manifest_tag > > 4 ) & 0xF ) ;
mydata - > internal_file_start = halt_offset + manifest_len + 4 ;
mydata - > has_compressed_files = compressed ;
mydata - > fp = fp ;
mydata - > refcount = 0 ;
zend_hash_add ( & ( PHAR_GLOBALS - > phar_fname_map ) , fname , fname_len , ( void * ) & mydata , sizeof ( phar_archive_data ) , NULL ) ;
2006-01-12 05:19:46 +08:00
if ( register_alias ) {
2006-03-09 04:07:25 +08:00
zend_hash_add ( & ( PHAR_GLOBALS - > phar_alias_map ) , alias , alias_len , ( void * ) & mydata , sizeof ( phar_archive_data * ) , NULL ) ;
2006-01-12 05:19:46 +08:00
}
2005-12-05 04:35:38 +08:00
efree ( savebuf ) ;
2006-01-04 10:26:15 +08:00
2006-02-28 09:36:30 +08:00
if ( pphar ) {
2006-03-09 04:07:25 +08:00
* pphar = mydata ;
2006-02-28 09:36:30 +08:00
}
2006-01-04 10:26:15 +08:00
return SUCCESS ;
}
/* }}} */
2006-03-04 10:12:22 +08:00
static int phar_open_filename ( char * fname , int fname_len , char * alias , int alias_len , phar_archive_data * * pphar TSRMLS_DC ) /* { { { */
2006-01-04 10:26:15 +08:00
{
const char token [ ] = " __HALT_COMPILER(); " ;
char * pos , buffer [ 1024 + sizeof ( token ) ] ;
const long readsize = sizeof ( buffer ) - sizeof ( token ) ;
const long tokenlen = sizeof ( token ) - 1 ;
long halt_offset ;
php_stream * fp ;
2006-03-04 10:12:22 +08:00
phar_archive_data * phar ;
2006-02-28 09:36:30 +08:00
2006-03-04 10:12:22 +08:00
if ( ( phar = phar_get_archive ( fname , fname_len , alias , alias_len TSRMLS_CC ) ) ! = NULL ) {
2006-02-28 09:36:30 +08:00
if ( fname_len ! = phar - > fname_len | | strncmp ( fname , phar - > fname , fname_len ) ) {
php_error_docref ( NULL TSRMLS_CC , E_RECOVERABLE_ERROR , " alias \" %s \" is already used for archive \" %s \" cannot be overloaded with \" %s \" " , alias , phar - > fname , fname ) ;
return FAILURE ;
} else {
if ( pphar ) {
* pphar = phar ;
}
return SUCCESS ;
}
}
2006-01-04 10:26:15 +08:00
2006-03-09 04:31:23 +08:00
# if PHP_MAJOR_VERSION < 6
2006-01-05 19:32:05 +08:00
if ( PG ( safe_mode ) & & ( ! php_checkuid ( fname , NULL , CHECKUID_ALLOW_ONLY_FILE ) ) ) {
return FAILURE ;
}
2006-03-09 04:31:23 +08:00
# endif
2006-01-05 19:32:05 +08:00
if ( php_check_open_basedir ( fname TSRMLS_CC ) ) {
return FAILURE ;
}
2006-01-04 10:26:15 +08:00
fp = php_stream_open_wrapper ( fname , " rb " , IGNORE_URL | STREAM_MUST_SEEK | REPORT_ERRORS , NULL ) ;
if ( ! fp ) {
2006-01-10 14:46:17 +08:00
php_error_docref ( NULL TSRMLS_CC , E_RECOVERABLE_ERROR , " unable to open phar for reading \" %s \" " , fname ) ;
2006-01-04 10:26:15 +08:00
return FAILURE ;
}
/* Maybe it's better to compile the file instead of just searching, */
/* but we only want the offset. So we want a .re scanner to find it. */
if ( - 1 = = php_stream_seek ( fp , 0 , SEEK_SET ) ) {
2006-01-05 08:39:31 +08:00
MAPPHAR_ALLOC_FAIL ( " cannot rewind phar \" %s \" " )
2006-01-04 10:26:15 +08:00
}
buffer [ sizeof ( buffer ) - 1 ] = ' \0 ' ;
memset ( buffer , 32 , sizeof ( token ) ) ;
halt_offset = 0 ;
while ( ! php_stream_eof ( fp ) ) {
if ( php_stream_read ( fp , buffer + tokenlen , readsize ) < 0 ) {
MAPPHAR_ALLOC_FAIL ( " internal corruption of phar \" %s \" (truncated manifest) " )
}
if ( ( pos = strstr ( buffer , token ) ) ! = NULL ) {
2006-01-05 08:39:31 +08:00
halt_offset + = ( pos - buffer ) ; /* no -tokenlen+tokenlen here */
2006-02-28 09:36:30 +08:00
return phar_open_file ( fp , fname , fname_len , alias , alias_len , halt_offset , pphar TSRMLS_CC ) ;
2006-01-04 10:26:15 +08:00
}
halt_offset + = readsize ;
memmove ( buffer , buffer + tokenlen , readsize + 1 ) ;
}
MAPPHAR_ALLOC_FAIL ( " internal corruption of phar \" %s \" (__HALT_COMPILER(); not found) " )
2005-12-05 12:47:29 +08:00
php_stream_close ( fp ) ;
2006-01-04 10:26:15 +08:00
return FAILURE ;
}
/* }}} */
2006-02-28 09:36:30 +08:00
static int phar_split_fname ( char * filename , int filename_len , char * * arch , int * arch_len , char * * entry , int * entry_len TSRMLS_DC ) /* { { { */
2006-01-04 10:26:15 +08:00
{
2006-01-11 09:51:47 +08:00
char * pos_p , * pos_z , * ext_str ;
2006-02-28 09:36:30 +08:00
int ext_len ;
2006-01-04 10:26:15 +08:00
if ( ! strncasecmp ( filename , " phar:// " , 7 ) ) {
filename + = 7 ;
2006-02-28 09:36:30 +08:00
filename_len - = 7 ;
}
pos_p = strstr ( filename , " .phar.php " ) ;
pos_z = strstr ( filename , " .phar.gz " ) ;
if ( pos_p ) {
if ( pos_z ) {
return FAILURE ;
}
ext_str = pos_p ;
ext_len = 9 ;
} else if ( pos_z ) {
ext_str = pos_z ;
ext_len = 8 ;
} else if ( ( pos_p = strstr ( filename , " .phar " ) ) ! = NULL ) {
ext_str = pos_p ;
ext_len = 5 ;
} else {
return FAILURE ;
}
* arch_len = ext_str - filename + ext_len ;
* arch = estrndup ( filename , * arch_len ) ;
if ( ext_str [ ext_len ] ) {
* entry_len = filename_len - * arch_len ;
* entry = estrndup ( ext_str + ext_len , * entry_len ) ;
} else {
* entry_len = 1 ;
* entry = estrndup ( " / " , 1 ) ;
}
return SUCCESS ;
}
/* }}} */
static php_url * phar_open_url ( php_stream_wrapper * wrapper , char * filename , char * mode , int options TSRMLS_DC ) /* { { { */
{
php_url * resource ;
char * arch , * entry ;
int arch_len , entry_len ;
if ( ! strncasecmp ( filename , " phar:// " , 7 ) ) {
if ( phar_split_fname ( filename , strlen ( filename ) , & arch , & arch_len , & entry , & entry_len TSRMLS_CC ) = = FAILURE ) {
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , " phar error: invalid url \" %s \" (cannot contain .phar.php and .phar.gz) " , filename ) ;
2006-01-04 10:26:15 +08:00
return NULL ;
}
2006-02-28 09:36:30 +08:00
resource = ecalloc ( 1 , sizeof ( php_url ) ) ;
2006-01-04 10:26:15 +08:00
resource - > scheme = estrndup ( " phar " , 4 ) ;
2006-02-28 09:36:30 +08:00
resource - > host = arch ;
resource - > path = entry ;
2006-01-04 10:26:15 +08:00
# if MBO_0
if ( resource ) {
fprintf ( stderr , " Alias: %s \n " , alias ) ;
fprintf ( stderr , " Scheme: %s \n " , resource - > scheme ) ;
/* fprintf(stderr, "User: %s\n", resource->user);*/
/* fprintf(stderr, "Pass: %s\n", resource->pass ? "***" : NULL);*/
fprintf ( stderr , " Host: %s \n " , resource - > host ) ;
/* fprintf(stderr, "Port: %d\n", resource->port);*/
fprintf ( stderr , " Path: %s \n " , resource - > path ) ;
/* fprintf(stderr, "Query: %s\n", resource->query);*/
/* fprintf(stderr, "Fragment: %s\n", resource->fragment);*/
}
# endif
2006-02-28 09:36:30 +08:00
if ( phar_open_filename ( resource - > host , arch_len , NULL , 0 , NULL TSRMLS_CC ) = = FAILURE )
2006-01-04 10:26:15 +08:00
{
php_url_free ( resource ) ;
return NULL ;
}
return resource ;
}
return NULL ;
2005-12-05 04:35:38 +08:00
}
/* }}} */
2006-01-10 14:46:17 +08:00
static int phar_open_compiled_file ( char * alias , int alias_len TSRMLS_DC ) /* { { { */
2006-01-04 10:26:15 +08:00
{
char * fname ;
long halt_offset ;
zval * halt_constant ;
php_stream * fp ;
fname = zend_get_executed_filename ( TSRMLS_C ) ;
if ( ! strcmp ( fname , " [no active file] " ) ) {
2006-01-10 14:46:17 +08:00
php_error_docref ( NULL TSRMLS_CC , E_RECOVERABLE_ERROR , " cannot initialize a phar outside of PHP execution " ) ;
2006-01-04 10:26:15 +08:00
return FAILURE ;
}
MAKE_STD_ZVAL ( halt_constant ) ;
if ( 0 = = zend_get_constant ( " __COMPILER_HALT_OFFSET__ " , 24 , halt_constant TSRMLS_CC ) ) {
2006-01-07 04:43:19 +08:00
FREE_ZVAL ( halt_constant ) ;
2006-01-10 14:46:17 +08:00
php_error_docref ( NULL TSRMLS_CC , E_RECOVERABLE_ERROR , " __HALT_COMPILER(); must be declared in a phar " ) ;
2006-01-04 10:26:15 +08:00
return FAILURE ;
}
halt_offset = Z_LVAL ( * halt_constant ) ;
2006-01-07 04:34:31 +08:00
zval_ptr_dtor ( & halt_constant ) ;
2006-01-04 10:26:15 +08:00
fp = php_stream_open_wrapper ( fname , " rb " , IGNORE_URL | STREAM_MUST_SEEK | REPORT_ERRORS , NULL ) ;
if ( ! fp ) {
2006-01-10 14:46:17 +08:00
php_error_docref ( NULL TSRMLS_CC , E_RECOVERABLE_ERROR , " unable to open phar for reading \" %s \" " , fname ) ;
2006-01-04 10:26:15 +08:00
return FAILURE ;
}
2006-02-28 09:36:30 +08:00
return phar_open_file ( fp , fname , strlen ( fname ) , alias , alias_len , halt_offset , NULL TSRMLS_CC ) ;
2006-01-04 10:26:15 +08:00
}
/* }}} */
2006-01-10 14:46:17 +08:00
/* {{{ proto mixed Phar::mapPhar([string alias])
* Reads the currently executed file ( a phar ) and registers its manifest */
2006-01-04 10:26:15 +08:00
PHP_METHOD ( Phar , mapPhar )
{
2006-01-10 14:46:17 +08:00
char * alias = NULL ;
int alias_len = 0 ;
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " |s " , & alias , & alias_len ) = = FAILURE ) {
2006-01-04 10:26:15 +08:00
return ;
}
2006-01-10 14:46:17 +08:00
RETURN_BOOL ( phar_open_compiled_file ( alias , alias_len TSRMLS_CC ) = = SUCCESS ) ;
2006-01-04 10:26:15 +08:00
} /* }}} */
2006-01-10 14:46:17 +08:00
/* {{{ proto mixed Phar::loadPhar(string url [, string alias])
2006-01-07 01:23:42 +08:00
* Loads a phar archive with an alias */
PHP_METHOD ( Phar , loadPhar )
{
2006-01-10 14:46:17 +08:00
char * fname , * alias = NULL ;
int fname_len , alias_len = 0 ;
2006-01-07 01:23:42 +08:00
2006-01-10 14:46:17 +08:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " s|s " , & fname , & fname_len , & alias , & alias_len ) = = FAILURE ) {
2006-01-07 01:23:42 +08:00
return ;
}
2006-02-28 09:36:30 +08:00
RETURN_BOOL ( phar_open_filename ( fname , fname_len , alias , alias_len , NULL TSRMLS_CC ) = = SUCCESS ) ;
2006-01-07 01:23:42 +08:00
} /* }}} */
2005-12-05 04:35:38 +08:00
static php_stream_ops phar_ops = {
2005-12-08 15:38:44 +08:00
phar_write , /* write (does nothing) */
phar_read , /* read */
phar_close , /* close */
phar_flush , /* flush (does nothing) */
2005-12-05 04:35:38 +08:00
" phar stream " ,
2005-12-12 14:17:16 +08:00
phar_seek , /* seek */
2005-12-08 15:38:44 +08:00
NULL , /* cast */
phar_stat , /* stat */
NULL , /* set option */
2005-12-05 04:35:38 +08:00
} ;
static php_stream_ops phar_dir_ops = {
2005-12-08 15:38:44 +08:00
phar_write , /* write (does nothing) */
phar_readdir , /* read */
phar_closedir , /* close */
phar_flush , /* flush (does nothing) */
2005-12-05 04:35:38 +08:00
" phar stream " ,
2006-01-04 10:26:15 +08:00
phar_seekdir , /* seek */
2005-12-08 15:38:44 +08:00
NULL , /* cast */
2005-12-11 15:25:30 +08:00
phar_stat , /* stat */
2005-12-08 15:38:44 +08:00
NULL , /* set option */
2005-12-05 04:35:38 +08:00
} ;
static php_stream_wrapper_ops phar_stream_wops = {
php_stream_phar_url_wrapper ,
NULL , /* stream_close */
2005-12-08 15:38:44 +08:00
NULL , /* php_stream_phar_stat, */
2005-12-05 04:35:38 +08:00
phar_stream_stat , /* stat_url */
phar_opendir , /* opendir */
" phar " ,
NULL , /* unlink */
NULL , /* rename */
NULL , /* create directory */
NULL /* remove directory */
} ;
php_stream_wrapper php_stream_phar_wrapper = {
& phar_stream_wops ,
NULL ,
0 /* is_url */
} ;
2006-02-28 09:36:30 +08:00
static int phar_postprocess_file ( php_stream_wrapper * wrapper , int options , phar_entry_data * idata , php_uint32 crc32 TSRMLS_DC ) /* { { { */
2005-12-05 04:35:38 +08:00
{
unsigned int crc = ~ 0 ;
2006-01-06 06:24:41 +08:00
int len = idata - > internal_file - > uncompressed_filesize ;
char c ;
2006-01-05 08:39:31 +08:00
2006-01-06 06:24:41 +08:00
php_stream_seek ( idata - > fp , 0 , SEEK_SET ) ;
while ( len - - ) {
php_stream_read ( idata - > fp , & c , 1 ) ;
2006-01-10 14:46:17 +08:00
CRC32 ( crc , c ) ;
2005-12-05 04:35:38 +08:00
}
2006-01-06 06:24:41 +08:00
php_stream_seek ( idata - > fp , 0 , SEEK_SET ) ;
2005-12-05 04:35:38 +08:00
if ( ~ crc = = crc32 ) {
2006-01-06 06:24:41 +08:00
return SUCCESS ;
2005-12-05 04:35:38 +08:00
} else {
2006-01-12 05:19:46 +08:00
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , " phar error: internal corruption of phar \" %s \" (crc32 mismatch on file \" %s \" ) " , idata - > phar - > fname , idata - > internal_file - > filename ) ;
2006-01-06 06:24:41 +08:00
return FAILURE ;
2005-12-05 04:35:38 +08:00
}
}
2006-01-03 23:59:07 +08:00
/* }}} */
2005-12-05 04:35:38 +08:00
2006-02-28 09:36:30 +08:00
static char * phar_decompress_filter ( phar_entry_info * entry , int return_unknow ) /* { { { */
2006-01-13 05:16:29 +08:00
{
switch ( entry - > flags & PHAR_ENT_COMPRESSION_MASK ) {
case PHAR_ENT_COMPRESSED_GZ :
return " zlib.inflate " ;
case PHAR_ENT_COMPRESSED_BZ2 :
return " bzip2.decompress " ;
default :
return return_unknow ? " unknown " : NULL ;
}
}
/* }}} */
2006-01-04 23:50:45 +08:00
static php_stream * php_stream_phar_url_wrapper ( php_stream_wrapper * wrapper , char * path , char * mode , int options , char * * opened_path , php_stream_context * context STREAMS_DC TSRMLS_DC ) /* { { { */
2005-12-05 04:35:38 +08:00
{
2006-02-28 09:36:30 +08:00
phar_entry_data * idata ;
2005-12-05 04:35:38 +08:00
char * internal_file ;
char * buffer ;
2006-01-13 05:16:29 +08:00
char * filter_name ;
2006-01-06 06:24:41 +08:00
char tmpbuf [ 8 ] ;
2005-12-05 04:35:38 +08:00
php_url * resource = NULL ;
2006-01-12 07:55:57 +08:00
php_stream * fp , * fpf ;
2006-01-12 10:33:28 +08:00
php_stream_filter * filter , * consumed ;
2005-12-10 07:37:03 +08:00
php_uint32 offset ;
2005-12-05 04:35:38 +08:00
2005-12-07 14:39:03 +08:00
resource = php_url_parse ( path ) ;
2006-01-04 10:26:15 +08:00
2006-01-04 17:26:32 +08:00
if ( ! resource & & ( resource = phar_open_url ( wrapper , path , mode , options TSRMLS_CC ) ) = = NULL ) {
2006-01-04 10:26:15 +08:00
return NULL ;
}
2006-01-02 04:40:43 +08:00
/* we must have at the very least phar://alias.phar/internalfile.php */
2006-02-28 09:36:30 +08:00
if ( ! resource - > scheme | | ! resource - > host | | ! resource - > path ) {
php_url_free ( resource ) ;
2005-12-11 08:00:31 +08:00
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , " phar error: invalid url \" %s \" " , path ) ;
2005-12-07 14:39:03 +08:00
return NULL ;
2005-12-05 04:35:38 +08:00
}
if ( strcasecmp ( " phar " , resource - > scheme ) ) {
2006-02-28 09:36:30 +08:00
php_url_free ( resource ) ;
2005-12-11 08:00:31 +08:00
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , " phar error: not a phar stream url \" %s \" " , path ) ;
2005-12-07 14:39:03 +08:00
return NULL ;
2005-12-05 04:35:38 +08:00
}
2005-12-10 07:37:03 +08:00
/* strip leading "/" */
2006-01-04 23:27:18 +08:00
internal_file = estrdup ( resource - > path + 1 ) ;
2006-02-28 09:36:30 +08:00
if ( NULL = = ( idata = phar_get_entry_data ( resource - > host , strlen ( resource - > host ) , internal_file , strlen ( internal_file ) TSRMLS_CC ) ) ) {
2006-01-01 15:40:36 +08:00
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , " phar error: \" %s \" is not a file in phar \" %s \" " , internal_file , resource - > host ) ;
2005-12-10 07:37:03 +08:00
efree ( internal_file ) ;
2006-01-04 23:27:18 +08:00
php_url_free ( resource ) ;
2005-12-05 04:35:38 +08:00
return NULL ;
}
2006-02-28 09:36:30 +08:00
php_url_free ( resource ) ;
2006-01-04 23:27:18 +08:00
# if MBO_0
2006-01-10 14:46:17 +08:00
fprintf ( stderr , " Pharname: %s \n " , idata - > phar - > filename ) ;
fprintf ( stderr , " Filename: %s \n " , internal_file ) ;
fprintf ( stderr , " Entry: %s \n " , idata - > internal_file - > filename ) ;
fprintf ( stderr , " Size: %u \n " , idata - > internal_file - > uncompressed_filesize ) ;
fprintf ( stderr , " Compressed: %u \n " , idata - > internal_file - > flags ) ;
fprintf ( stderr , " Offset: %u \n " , idata - > internal_file - > offset_within_phar ) ;
fprintf ( stderr , " Cached: %s \n " , idata - > internal_file - > filedata ? " yes " : " no " ) ;
2006-01-04 23:27:18 +08:00
# endif
2005-12-05 04:35:38 +08:00
2006-01-04 23:27:18 +08:00
/* do we have the data already? */
2006-01-06 06:24:41 +08:00
if ( idata - > fp ) {
2006-01-12 07:55:57 +08:00
fpf = php_stream_alloc ( & phar_ops , idata , NULL , mode ) ;
2006-03-11 07:52:57 +08:00
idata - > phar - > refcount + + ;
2006-01-04 23:27:18 +08:00
efree ( internal_file ) ;
2006-01-12 07:55:57 +08:00
return fpf ;
2006-01-04 23:27:18 +08:00
}
2005-12-05 04:35:38 +08:00
2006-03-09 04:31:23 +08:00
# if PHP_MAJOR_VERSION < 6
2006-01-12 05:19:46 +08:00
if ( PG ( safe_mode ) & & ( ! php_checkuid ( idata - > phar - > fname , NULL , CHECKUID_ALLOW_ONLY_FILE ) ) ) {
2006-01-04 23:27:18 +08:00
efree ( idata ) ;
2005-12-10 07:37:03 +08:00
efree ( internal_file ) ;
2005-12-05 12:47:29 +08:00
return NULL ;
}
2006-03-09 04:31:23 +08:00
# endif
2006-01-04 23:27:18 +08:00
2006-01-12 05:19:46 +08:00
if ( php_check_open_basedir ( idata - > phar - > fname TSRMLS_CC ) ) {
2006-01-04 23:27:18 +08:00
efree ( idata ) ;
2005-12-10 07:37:03 +08:00
efree ( internal_file ) ;
2005-12-05 12:47:29 +08:00
return NULL ;
2005-12-05 04:35:38 +08:00
}
2005-12-05 12:47:29 +08:00
2006-01-04 23:27:18 +08:00
fp = idata - > phar - > fp ;
2005-12-05 12:47:29 +08:00
2005-12-05 04:35:38 +08:00
if ( ! fp ) {
2006-01-12 05:19:46 +08:00
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , " phar error: cannot open phar \" %s \" " , idata - > phar - > fname ) ;
2005-12-05 04:35:38 +08:00
efree ( idata ) ;
2005-12-10 07:37:03 +08:00
efree ( internal_file ) ;
2005-12-05 04:35:38 +08:00
return NULL ;
}
/* seek to start of internal file and read it */
2006-01-04 23:27:18 +08:00
offset = idata - > phar - > internal_file_start + idata - > internal_file - > offset_within_phar ;
if ( - 1 = = php_stream_seek ( fp , offset , SEEK_SET ) ) {
2005-12-11 08:00:31 +08:00
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , " phar error: internal corruption of phar \" %s \" (cannot seek to start of file \" %s \" at offset \" %d \" ) " ,
2006-01-12 05:19:46 +08:00
idata - > phar - > fname , internal_file , offset ) ;
2006-01-04 23:27:18 +08:00
efree ( idata ) ;
2005-12-11 08:00:31 +08:00
efree ( internal_file ) ;
2005-12-10 07:37:03 +08:00
return NULL ;
}
2006-01-04 23:27:18 +08:00
2006-01-13 05:16:29 +08:00
if ( ( idata - > internal_file - > flags & PHAR_ENT_COMPRESSION_MASK ) ! = 0 ) {
;
if ( ( filter_name = phar_decompress_filter ( idata - > internal_file , 0 ) ) ! = NULL ) {
filter = php_stream_filter_create ( phar_decompress_filter ( idata - > internal_file , 0 ) , NULL , php_stream_is_persistent ( fp ) TSRMLS_CC ) ;
} else {
filter = NULL ;
}
2006-01-12 07:55:57 +08:00
if ( ! filter ) {
2006-01-13 05:16:29 +08:00
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , " phar error: unable to read phar \" %s \" (cannot create %s filter while decompressing file \" %s \" ) " , idata - > phar - > fname , phar_decompress_filter ( idata - > internal_file , 1 ) , internal_file ) ;
2005-12-05 04:35:38 +08:00
efree ( idata ) ;
2005-12-11 08:00:31 +08:00
efree ( internal_file ) ;
2006-01-12 07:55:57 +08:00
return NULL ;
2005-12-05 04:35:38 +08:00
}
2006-01-13 05:16:29 +08:00
/* Unfortunatley we cannot check the read position of fp after getting */
2006-01-12 10:33:28 +08:00
/* uncompressed data because the new stream posiition is being changed */
/* by the number of bytes read throughthe filter not by the raw number */
/* bytes being consumed on the stream. Therefor use a consumed filter. */
consumed = php_stream_filter_create ( " consumed " , NULL , php_stream_is_persistent ( fp ) TSRMLS_CC ) ;
php_stream_filter_append ( & fp - > readfilters , consumed ) ;
2006-01-12 07:55:57 +08:00
php_stream_filter_append ( & fp - > readfilters , filter ) ;
2005-12-05 04:35:38 +08:00
2006-01-12 07:55:57 +08:00
idata - > fp = php_stream_temp_new ( ) ;
if ( php_stream_copy_to_stream ( fp , idata - > fp , idata - > internal_file - > uncompressed_filesize ) ! = idata - > internal_file - > uncompressed_filesize ) {
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , " phar error: internal corruption of phar \" %s \" (actual filesize mismatch on file \" %s \" ) " , idata - > phar - > fname , internal_file ) ;
php_stream_close ( idata - > fp ) ;
2005-12-05 04:35:38 +08:00
efree ( idata ) ;
2005-12-11 07:19:32 +08:00
efree ( internal_file ) ;
2005-12-05 04:35:38 +08:00
return NULL ;
}
2006-01-12 07:55:57 +08:00
php_stream_filter_flush ( filter , 1 ) ;
php_stream_filter_remove ( filter , 1 TSRMLS_CC ) ;
2006-01-12 10:33:28 +08:00
php_stream_filter_flush ( consumed , 1 ) ;
php_stream_filter_remove ( consumed , 1 TSRMLS_CC ) ;
if ( offset + idata - > internal_file - > compressed_filesize ! = php_stream_tell ( fp ) ) {
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , " phar error: internal corruption of phar \" %s \" (actual filesize mismatch on file \" %s \" ) " , idata - > phar - > fname , internal_file ) ;
php_stream_close ( idata - > fp ) ;
efree ( idata ) ;
efree ( internal_file ) ;
return NULL ;
}
2006-01-12 07:55:57 +08:00
php_stream_seek ( fp , offset + idata - > internal_file - > compressed_filesize , SEEK_SET ) ;
2006-01-02 06:11:03 +08:00
} else { /* from here is for non-compressed */
2006-01-06 06:24:41 +08:00
buffer = & tmpbuf [ 0 ] ;
/* bypass to temp stream */
idata - > fp = php_stream_temp_new ( ) ;
2006-01-10 14:46:17 +08:00
if ( php_stream_copy_to_stream ( fp , idata - > fp , idata - > internal_file - > uncompressed_filesize ) ! = idata - > internal_file - > uncompressed_filesize ) {
2006-01-12 05:19:46 +08:00
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , " phar error: internal corruption of phar \" %s \" (actual filesize mismatch on file \" %s \" ) " , idata - > phar - > fname , internal_file ) ;
2006-01-06 06:24:41 +08:00
php_stream_close ( idata - > fp ) ;
2005-12-05 04:35:38 +08:00
efree ( idata ) ;
2005-12-11 08:00:31 +08:00
efree ( internal_file ) ;
2005-12-05 04:35:38 +08:00
return NULL ;
}
}
2006-01-12 07:55:57 +08:00
/* check length, crc32 */
if ( phar_postprocess_file ( wrapper , options , idata , idata - > internal_file - > crc32 TSRMLS_CC ) ! = SUCCESS ) {
php_stream_close ( idata - > fp ) ;
efree ( idata ) ;
efree ( internal_file ) ;
return NULL ;
}
idata - > internal_file - > crc_checked = 1 ;
fpf = php_stream_alloc ( & phar_ops , idata , NULL , mode ) ;
2006-03-11 07:52:57 +08:00
idata - > phar - > refcount + + ;
2005-12-10 07:37:03 +08:00
efree ( internal_file ) ;
2006-01-12 07:55:57 +08:00
return fpf ;
2005-12-05 04:35:38 +08:00
}
/* }}} */
2006-01-04 23:50:45 +08:00
static int phar_close ( php_stream * stream , int close_handle TSRMLS_DC ) /* { { { */
2005-12-05 04:35:38 +08:00
{
2006-02-28 09:36:30 +08:00
phar_entry_data * data = ( phar_entry_data * ) stream - > abstract ;
2005-12-05 04:35:38 +08:00
2006-01-10 14:46:17 +08:00
/* data->fp is the temporary memory stream containing this file's data */
2006-01-06 06:24:41 +08:00
if ( data - > fp ) {
2006-01-10 14:46:17 +08:00
/* only close if we have a cached temp memory stream */
2006-01-06 06:24:41 +08:00
if ( data - > internal_file - > fp ) {
php_stream_close ( data - > fp ) ;
} else {
data - > internal_file - > fp = data - > fp ;
}
}
2006-03-11 07:52:57 +08:00
if ( - - data - > phar - > refcount < 0 ) {
phar_destroy_phar_data ( data - > phar TSRMLS_CC ) ;
}
2006-01-06 06:24:41 +08:00
2005-12-05 04:35:38 +08:00
efree ( data ) ;
return 0 ;
}
2006-01-03 23:59:07 +08:00
/* }}} */
2005-12-05 04:35:38 +08:00
2006-01-04 23:50:45 +08:00
static int phar_closedir ( php_stream * stream , int close_handle TSRMLS_DC ) /* { { { */
2005-12-05 16:31:05 +08:00
{
HashTable * data = ( HashTable * ) stream - > abstract ;
2006-01-02 06:19:51 +08:00
if ( data )
{
zend_hash_destroy ( data ) ;
FREE_HASHTABLE ( data ) ;
stream - > abstract = NULL ;
}
2005-12-05 16:31:05 +08:00
return 0 ;
}
2006-01-03 23:59:07 +08:00
/* }}} */
2005-12-05 16:31:05 +08:00
2006-01-04 23:50:45 +08:00
static int phar_seekdir ( php_stream * stream , off_t offset , int whence , off_t * newoffset TSRMLS_DC ) /* { { { */
2006-01-04 10:26:15 +08:00
{
HashTable * data = ( HashTable * ) stream - > abstract ;
if ( data )
{
if ( whence = = SEEK_END ) {
whence = SEEK_SET ;
offset = zend_hash_num_elements ( data ) + offset ;
}
if ( whence = = SEEK_SET ) {
zend_hash_internal_pointer_reset ( data ) ;
}
if ( offset < 0 ) {
php_stream_wrapper_log_error ( stream - > wrapper , stream - > flags TSRMLS_CC , " phar error: cannot seek because the resulting seek is negative " ) ;
return - 1 ;
} else {
* newoffset = 0 ;
while ( * newoffset < offset & & zend_hash_move_forward ( data ) = = SUCCESS ) {
( * newoffset ) + + ;
}
return 0 ;
}
}
return - 1 ;
}
/* }}} */
2006-01-04 23:50:45 +08:00
static size_t phar_read ( php_stream * stream , char * buf , size_t count TSRMLS_DC ) /* { { { */
2005-12-05 04:35:38 +08:00
{
2006-02-28 09:36:30 +08:00
phar_entry_data * data = ( phar_entry_data * ) stream - > abstract ;
2005-12-05 04:35:38 +08:00
2006-02-28 22:44:23 +08:00
size_t got = php_stream_read ( data - > fp , buf , count ) ;
if ( data - > fp - > eof ) {
stream - > eof = 1 ;
}
return got ;
2005-12-05 04:35:38 +08:00
}
2006-01-03 23:59:07 +08:00
/* }}} */
2005-12-05 04:35:38 +08:00
2006-01-04 23:50:45 +08:00
static size_t phar_readdir ( php_stream * stream , char * buf , size_t count TSRMLS_DC ) /* { { { */
2005-12-05 04:35:38 +08:00
{
size_t to_read ;
2005-12-05 16:31:05 +08:00
HashTable * data = ( HashTable * ) stream - > abstract ;
char * key ;
uint keylen ;
ulong unused ;
2005-12-05 04:35:38 +08:00
2005-12-05 16:31:05 +08:00
if ( FAILURE = = zend_hash_has_more_elements ( data ) ) {
return 0 ;
}
if ( HASH_KEY_NON_EXISTANT = = zend_hash_get_current_key_ex ( data , & key , & keylen , & unused , 0 , NULL ) ) {
2005-12-05 04:35:38 +08:00
return 0 ;
}
2005-12-05 16:31:05 +08:00
zend_hash_move_forward ( data ) ;
to_read = MIN ( keylen , count ) ;
if ( to_read = = 0 | | count < keylen ) {
return 0 ;
}
memset ( buf , 0 , sizeof ( php_stream_dirent ) ) ;
memcpy ( ( ( php_stream_dirent * ) buf ) - > d_name , key , to_read ) ;
( ( php_stream_dirent * ) buf ) - > d_name [ to_read + 1 ] = ' \0 ' ;
2005-12-05 04:35:38 +08:00
2005-12-05 16:31:05 +08:00
return sizeof ( php_stream_dirent ) ;
2005-12-05 04:35:38 +08:00
}
2006-01-03 23:59:07 +08:00
/* }}} */
2005-12-05 04:35:38 +08:00
2006-01-04 23:50:45 +08:00
static int phar_seek ( php_stream * stream , off_t offset , int whence , off_t * newoffset TSRMLS_DC ) /* { { { */
2005-12-05 04:35:38 +08:00
{
2006-02-28 09:36:30 +08:00
phar_entry_data * data = ( phar_entry_data * ) stream - > abstract ;
2006-01-06 06:24:41 +08:00
int res = php_stream_seek ( data - > fp , offset , whence ) ;
* newoffset = php_stream_tell ( data - > fp ) ;
return res ;
2005-12-05 04:35:38 +08:00
}
2006-01-03 23:59:07 +08:00
/* }}} */
2005-12-05 04:35:38 +08:00
2006-01-04 23:50:45 +08:00
static size_t phar_write ( php_stream * stream , const char * buf , size_t count TSRMLS_DC ) /* { { { */
2005-12-05 04:35:38 +08:00
{
return 0 ;
}
2006-01-03 23:59:07 +08:00
/* }}} */
2005-12-05 04:35:38 +08:00
2006-01-04 23:50:45 +08:00
static int phar_flush ( php_stream * stream TSRMLS_DC ) /* { { { */
2005-12-05 04:35:38 +08:00
{
return EOF ;
}
2006-01-03 23:59:07 +08:00
/* }}} */
2005-12-05 04:35:38 +08:00
2006-03-03 06:44:39 +08:00
/* {{{ phar_dostat */
2006-03-04 10:12:22 +08:00
static void phar_dostat ( phar_archive_data * phar , phar_entry_info * data , php_stream_statbuf * ssb ,
2006-03-03 06:44:39 +08:00
zend_bool is_dir , char * alias , int alias_len TSRMLS_DC )
2005-12-05 04:35:38 +08:00
{
2006-01-01 15:40:36 +08:00
char * tmp ;
int tmp_len ;
2005-12-05 04:35:38 +08:00
memset ( ssb , 0 , sizeof ( php_stream_statbuf ) ) ;
2005-12-11 15:25:30 +08:00
/* read-only across the board */
2005-12-05 04:35:38 +08:00
ssb - > sb . st_mode = 0444 ;
if ( ! is_dir ) {
ssb - > sb . st_size = data - > uncompressed_filesize ;
2005-12-11 15:25:30 +08:00
ssb - > sb . st_mode | = S_IFREG ; /* regular file */
/* timestamp is just the timestamp when this was added to the phar */
2005-12-05 04:35:38 +08:00
# ifdef NETWARE
ssb - > sb . st_mtime . tv_sec = data - > timestamp ;
ssb - > sb . st_atime . tv_sec = data - > timestamp ;
ssb - > sb . st_ctime . tv_sec = data - > timestamp ;
# else
ssb - > sb . st_mtime = data - > timestamp ;
ssb - > sb . st_atime = data - > timestamp ;
ssb - > sb . st_ctime = data - > timestamp ;
# endif
} else {
ssb - > sb . st_size = 0 ;
2005-12-11 15:25:30 +08:00
ssb - > sb . st_mode | = S_IFDIR ; /* regular directory */
2005-12-05 04:35:38 +08:00
# ifdef NETWARE
2006-03-03 06:44:39 +08:00
ssb - > sb . st_mtime . tv_sec = phar - > max_timestamp ;
ssb - > sb . st_atime . tv_sec = phar - > max_timestamp ;
ssb - > sb . st_ctime . tv_sec = phar - > max_timestamp ;
2005-12-05 04:35:38 +08:00
# else
2006-03-03 06:44:39 +08:00
ssb - > sb . st_mtime = phar - > max_timestamp ;
ssb - > sb . st_atime = phar - > max_timestamp ;
ssb - > sb . st_ctime = phar - > max_timestamp ;
2005-12-05 04:35:38 +08:00
# endif
}
ssb - > sb . st_nlink = 1 ;
ssb - > sb . st_rdev = - 1 ;
2006-01-01 15:40:36 +08:00
if ( data ) {
tmp_len = data - > filename_len + alias_len ;
} else {
tmp_len = alias_len + 1 ;
}
tmp = ( char * ) emalloc ( tmp_len ) ;
memcpy ( tmp , alias , alias_len ) ;
if ( data ) {
memcpy ( tmp + alias_len , data - > filename , data - > filename_len ) ;
} else {
* ( tmp + alias_len ) = ' / ' ;
}
/* this is only for APC, so use /dev/null device - no chance of conflict there! */
ssb - > sb . st_dev = 0xc ;
/* generate unique inode number for alias/filename, so no phars will conflict */
ssb - > sb . st_ino = zend_get_hash_value ( tmp , tmp_len ) ;
efree ( tmp ) ;
2005-12-07 09:18:54 +08:00
# ifndef PHP_WIN32
2005-12-05 04:35:38 +08:00
ssb - > sb . st_blksize = - 1 ;
ssb - > sb . st_blocks = - 1 ;
2005-12-07 09:18:54 +08:00
# endif
2005-12-05 04:35:38 +08:00
}
2006-01-03 23:59:07 +08:00
/* }}}*/
2005-12-05 04:35:38 +08:00
2006-03-03 06:44:39 +08:00
static int phar_stat ( php_stream * stream , php_stream_statbuf * ssb TSRMLS_DC ) /* { { { */
{
phar_entry_data * data ;
/* If ssb is NULL then someone is misbehaving */
if ( ! ssb ) return - 1 ;
data = ( phar_entry_data * ) stream - > abstract ;
phar_dostat ( data - > phar , data - > internal_file , ssb , 0 , data - > phar - > alias , data - > phar - > alias_len TSRMLS_CC ) ;
return 0 ;
}
/* }}} */
2006-01-04 23:50:45 +08:00
static int phar_stream_stat ( php_stream_wrapper * wrapper , char * url , int flags ,
2006-01-03 23:59:07 +08:00
php_stream_statbuf * ssb , php_stream_context * context TSRMLS_DC ) /* {{{ */
2005-12-05 04:35:38 +08:00
{
php_url * resource = NULL ;
char * internal_file , * key ;
uint keylen ;
ulong unused ;
2006-03-04 10:12:22 +08:00
phar_archive_data * phar ;
2006-02-28 09:36:30 +08:00
phar_entry_info * entry ;
2005-12-05 04:35:38 +08:00
resource = php_url_parse ( url ) ;
2006-01-04 10:26:15 +08:00
2006-01-04 17:26:32 +08:00
if ( ! resource & & ( resource = phar_open_url ( wrapper , url , " r " , 0 TSRMLS_CC ) ) = = NULL ) {
2006-01-04 10:26:15 +08:00
return - 1 ;
}
2006-01-02 04:40:43 +08:00
/* we must have at the very least phar://alias.phar/internalfile.php */
2006-02-28 09:36:30 +08:00
if ( ! resource - > scheme | | ! resource - > host | | ! resource - > path ) {
php_url_free ( resource ) ;
2005-12-11 08:00:31 +08:00
php_stream_wrapper_log_error ( wrapper , flags TSRMLS_CC , " phar error: invalid url \" %s \" " , url ) ;
2005-12-05 04:35:38 +08:00
return - 1 ;
}
if ( strcasecmp ( " phar " , resource - > scheme ) ) {
2005-12-07 14:39:03 +08:00
php_url_free ( resource ) ;
2005-12-11 08:00:31 +08:00
php_stream_wrapper_log_error ( wrapper , flags TSRMLS_CC , " phar error: not a phar url \" %s \" " , url ) ;
2005-12-07 14:39:03 +08:00
return - 1 ;
2005-12-05 04:35:38 +08:00
}
internal_file = resource - > path + 1 ; /* strip leading "/" */
2006-01-02 04:40:43 +08:00
/* find the phar in our trusty global hash indexed by alias (host of phar://blah.phar/file.whatever) */
2006-03-04 10:12:22 +08:00
if ( ( phar = phar_get_archive ( resource - > host , strlen ( resource - > host ) , NULL , 0 TSRMLS_CC ) ) ! = NULL ) {
2005-12-05 04:35:38 +08:00
if ( * internal_file = = ' \0 ' ) {
2005-12-08 15:38:44 +08:00
/* root directory requested */
2006-03-03 06:44:39 +08:00
phar_dostat ( phar , NULL , ssb , 1 , phar - > alias , phar - > alias_len TSRMLS_CC ) ;
2005-12-05 04:35:38 +08:00
php_url_free ( resource ) ;
return 0 ;
}
2005-12-11 15:25:30 +08:00
/* search through the manifest of files, and if we have an exact match, it's a file */
2006-01-11 09:51:47 +08:00
if ( SUCCESS = = zend_hash_find ( & phar - > manifest , internal_file , strlen ( internal_file ) , ( void * * ) & entry ) ) {
2006-03-03 06:44:39 +08:00
phar_dostat ( phar , entry , ssb , 0 , phar - > alias , phar - > alias_len TSRMLS_CC ) ;
2005-12-05 04:35:38 +08:00
} else {
2005-12-11 15:25:30 +08:00
/* search for directory (partial match of a file) */
2006-01-11 09:51:47 +08:00
zend_hash_internal_pointer_reset ( & phar - > manifest ) ;
while ( FAILURE ! = zend_hash_has_more_elements ( & phar - > manifest ) ) {
2005-12-05 16:31:05 +08:00
if ( HASH_KEY_NON_EXISTANT ! =
zend_hash_get_current_key_ex (
2006-01-11 09:51:47 +08:00
& phar - > manifest , & key , & keylen , & unused , 0 , NULL ) ) {
2005-12-11 15:25:30 +08:00
if ( 0 = = memcmp ( internal_file , key , strlen ( internal_file ) ) ) {
/* directory found, all dirs have the same stat */
2005-12-11 16:14:44 +08:00
if ( key [ strlen ( internal_file ) ] = = ' / ' ) {
2006-03-03 06:44:39 +08:00
phar_dostat ( phar , NULL , ssb , 1 , phar - > alias , phar - > alias_len TSRMLS_CC ) ;
2005-12-11 16:14:44 +08:00
break ;
}
2005-12-05 04:35:38 +08:00
}
}
2006-01-11 09:51:47 +08:00
if ( SUCCESS ! = zend_hash_move_forward ( & phar - > manifest ) ) {
2005-12-11 15:25:30 +08:00
break ;
}
2005-12-05 04:35:38 +08:00
}
}
}
php_url_free ( resource ) ;
return 0 ;
}
2006-01-03 23:59:07 +08:00
/* }}} */
2005-12-05 04:35:38 +08:00
2005-12-11 15:25:30 +08:00
/* add an empty element with a char * key to a hash table, avoiding duplicates */
2006-01-03 23:59:07 +08:00
static int phar_add_empty ( HashTable * ht , char * arKey , uint nKeyLength ) /* { { { */
2005-12-05 16:31:05 +08:00
{
void * dummy = ( void * ) 1 ;
return zend_hash_update ( ht , arKey , nKeyLength , & dummy , sizeof ( void * ) , NULL ) ;
}
2006-01-03 23:59:07 +08:00
/* }}} */
2005-12-05 16:31:05 +08:00
2006-01-03 23:59:07 +08:00
static int compare_dir_name ( const void * a , const void * b TSRMLS_DC ) /* { { { */
2006-01-02 04:16:09 +08:00
{
Bucket * f ;
Bucket * s ;
int result ;
f = * ( ( Bucket * * ) a ) ;
s = * ( ( Bucket * * ) b ) ;
2006-02-28 09:36:30 +08:00
# if (PHP_MAJOR_VERSION < 6)
result = zend_binary_strcmp ( f - > arKey , f - > nKeyLength , s - > arKey , s - > nKeyLength ) ;
# else
result = zend_binary_strcmp ( f - > key . arKey . s , f - > nKeyLength , s - > key . arKey . s , s - > nKeyLength ) ;
# endif
2006-01-02 04:16:09 +08:00
if ( result < 0 ) {
return - 1 ;
} else if ( result > 0 ) {
return 1 ;
} else {
return 0 ;
}
}
2006-01-03 23:59:07 +08:00
/* }}} */
2006-01-02 04:16:09 +08:00
2006-01-03 23:59:07 +08:00
static php_stream * phar_make_dirstream ( char * dir , HashTable * manifest TSRMLS_DC ) /* { { { */
2005-12-05 04:35:38 +08:00
{
2005-12-05 16:31:05 +08:00
HashTable * data ;
2005-12-05 04:35:38 +08:00
int dirlen = strlen ( dir ) ;
char * save , * found , * key ;
uint keylen ;
ulong unused ;
2005-12-05 16:31:05 +08:00
char * entry ;
ALLOC_HASHTABLE ( data ) ;
zend_hash_init ( data , 64 , zend_get_hash_value , NULL , 0 ) ;
2005-12-05 04:35:38 +08:00
zend_hash_internal_pointer_reset ( manifest ) ;
2006-01-11 09:51:47 +08:00
while ( FAILURE ! = zend_hash_has_more_elements ( manifest ) ) {
2005-12-05 16:31:05 +08:00
if ( HASH_KEY_NON_EXISTANT = = zend_hash_get_current_key_ex ( manifest , & key , & keylen , & unused , 0 , NULL ) ) {
2005-12-11 16:14:44 +08:00
break ;
2005-12-05 04:35:38 +08:00
}
if ( * dir = = ' / ' ) {
2005-12-11 16:14:44 +08:00
/* root directory */
2005-12-05 16:31:05 +08:00
if ( NULL ! = ( found = ( char * ) memchr ( key , ' / ' , keylen ) ) ) {
2005-12-08 15:38:44 +08:00
/* the entry has a path separator and is a subdirectory */
2005-12-11 16:14:44 +08:00
entry = ( char * ) emalloc ( found - key + 1 ) ;
memcpy ( entry , key , found - key ) ;
keylen = found - key ;
entry [ keylen ] = ' \0 ' ;
} else {
entry = ( char * ) emalloc ( keylen + 1 ) ;
memcpy ( entry , key , keylen ) ;
entry [ keylen ] = ' \0 ' ;
2005-12-05 04:35:38 +08:00
}
2005-12-11 16:14:44 +08:00
goto PHAR_ADD_ENTRY ;
2005-12-05 04:35:38 +08:00
} else {
if ( 0 ! = memcmp ( key , dir , dirlen ) ) {
2005-12-08 15:38:44 +08:00
/* entry in directory not found */
2005-12-11 16:14:44 +08:00
if ( SUCCESS ! = zend_hash_move_forward ( manifest ) ) {
break ;
}
2005-12-05 04:35:38 +08:00
continue ;
2005-12-11 16:14:44 +08:00
} else {
if ( key [ dirlen ] ! = ' / ' ) {
if ( SUCCESS ! = zend_hash_move_forward ( manifest ) ) {
break ;
}
continue ;
}
2005-12-05 04:35:38 +08:00
}
}
save = key ;
2005-12-08 15:38:44 +08:00
save + = dirlen + 1 ; /* seek to just past the path separator */
2005-12-05 04:35:38 +08:00
if ( NULL ! = ( found = ( char * ) memchr ( save , ' / ' , keylen - dirlen - 1 ) ) ) {
2005-12-08 15:38:44 +08:00
/* is subdirectory */
2005-12-05 16:31:05 +08:00
save - = dirlen + 1 ;
2005-12-11 16:14:44 +08:00
entry = ( char * ) emalloc ( found - save + dirlen + 1 ) ;
memcpy ( entry , save + dirlen + 1 , found - save - dirlen - 1 ) ;
keylen = found - save - dirlen - 1 ;
entry [ keylen ] = ' \0 ' ;
2005-12-05 04:35:38 +08:00
} else {
2005-12-08 15:38:44 +08:00
/* is file */
2005-12-05 16:31:05 +08:00
save - = dirlen + 1 ;
entry = ( char * ) emalloc ( keylen - dirlen + 1 ) ;
2005-12-11 16:14:44 +08:00
memcpy ( entry , save + dirlen + 1 , keylen - dirlen - 1 ) ;
entry [ keylen - dirlen - 1 ] = ' \0 ' ;
keylen = keylen - dirlen - 1 ;
2005-12-05 04:35:38 +08:00
}
2005-12-11 16:14:44 +08:00
PHAR_ADD_ENTRY :
2005-12-05 16:31:05 +08:00
phar_add_empty ( data , entry , keylen ) ;
efree ( entry ) ;
2005-12-11 16:14:44 +08:00
if ( SUCCESS ! = zend_hash_move_forward ( manifest ) ) {
break ;
}
}
2006-01-11 09:51:47 +08:00
if ( FAILURE ! = zend_hash_has_more_elements ( data ) ) {
2005-12-11 16:14:44 +08:00
efree ( dir ) ;
2006-01-02 04:16:09 +08:00
if ( zend_hash_sort ( data , zend_qsort , compare_dir_name , 0 TSRMLS_CC ) = = FAILURE ) {
FREE_HASHTABLE ( data ) ;
return NULL ;
}
2005-12-11 16:14:44 +08:00
return php_stream_alloc ( & phar_dir_ops , data , NULL , " r " ) ;
} else {
efree ( dir ) ;
FREE_HASHTABLE ( data ) ;
return NULL ;
2005-12-05 04:35:38 +08:00
}
}
2006-01-03 23:59:07 +08:00
/* }}}*/
2005-12-05 04:35:38 +08:00
2006-01-04 23:50:45 +08:00
static php_stream * phar_opendir ( php_stream_wrapper * wrapper , char * filename , char * mode ,
2006-01-03 23:59:07 +08:00
int options , char * * opened_path , php_stream_context * context STREAMS_DC TSRMLS_DC ) /* {{{ */
2005-12-05 04:35:38 +08:00
{
php_url * resource = NULL ;
php_stream * ret ;
char * internal_file , * key ;
uint keylen ;
ulong unused ;
2006-03-04 10:12:22 +08:00
phar_archive_data * phar ;
2006-02-28 09:36:30 +08:00
phar_entry_info * entry ;
2005-12-05 04:35:38 +08:00
resource = php_url_parse ( filename ) ;
2006-01-04 10:26:15 +08:00
2006-01-04 17:26:32 +08:00
if ( ! resource & & ( resource = phar_open_url ( wrapper , filename , mode , options TSRMLS_CC ) ) = = NULL ) {
2006-01-04 10:26:15 +08:00
return NULL ;
}
2006-01-02 04:40:43 +08:00
/* we must have at the very least phar://alias.phar/ */
2006-02-28 09:36:30 +08:00
if ( ! resource - > scheme | | ! resource - > host | | ! resource - > path ) {
if ( resource - > host & & ! resource - > path ) {
2006-01-02 04:40:43 +08:00
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , " phar error: no directory in \" %s \" , must have at least phar://%s/ for root directory " , filename , resource - > host ) ;
2005-12-11 15:25:30 +08:00
php_url_free ( resource ) ;
return NULL ;
}
2006-02-28 09:36:30 +08:00
php_url_free ( resource ) ;
2006-01-02 04:40:43 +08:00
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , " phar error: invalid url \" %s \" , must have at least phar://%s/ " , filename , filename ) ;
2005-12-07 14:39:03 +08:00
return NULL ;
2005-12-05 04:35:38 +08:00
}
if ( strcasecmp ( " phar " , resource - > scheme ) ) {
2005-12-07 14:39:03 +08:00
php_url_free ( resource ) ;
2005-12-11 08:00:31 +08:00
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , " phar error: not a phar url \" %s \" " , filename ) ;
2005-12-07 14:39:03 +08:00
return NULL ;
2005-12-05 04:35:38 +08:00
}
internal_file = resource - > path + 1 ; /* strip leading "/" */
2006-03-04 10:12:22 +08:00
if ( ( phar = phar_get_archive ( resource - > host , strlen ( resource - > host ) , NULL , 0 TSRMLS_CC ) ) ! = NULL ) {
2005-12-05 04:35:38 +08:00
if ( * internal_file = = ' \0 ' ) {
2005-12-08 15:38:44 +08:00
/* root directory requested */
2005-12-11 16:14:44 +08:00
internal_file = estrndup ( internal_file - 1 , 1 ) ;
2006-01-11 09:51:47 +08:00
ret = phar_make_dirstream ( internal_file , & phar - > manifest TSRMLS_CC ) ;
2005-12-05 04:35:38 +08:00
php_url_free ( resource ) ;
return ret ;
}
2006-01-11 09:51:47 +08:00
if ( SUCCESS = = zend_hash_find ( & phar - > manifest , internal_file , strlen ( internal_file ) , ( void * * ) & entry ) ) {
2005-12-05 04:35:38 +08:00
php_url_free ( resource ) ;
return NULL ;
} else {
2005-12-08 15:38:44 +08:00
/* search for directory */
2006-01-11 09:51:47 +08:00
zend_hash_internal_pointer_reset ( & phar - > manifest ) ;
while ( FAILURE ! = zend_hash_has_more_elements ( & phar - > manifest ) ) {
2005-12-05 16:31:05 +08:00
if ( HASH_KEY_NON_EXISTANT ! =
zend_hash_get_current_key_ex (
2006-01-11 09:51:47 +08:00
& phar - > manifest , & key , & keylen , & unused , 0 , NULL ) ) {
2005-12-11 16:14:44 +08:00
if ( 0 = = memcmp ( key , internal_file , strlen ( internal_file ) ) ) {
2005-12-08 15:38:44 +08:00
/* directory found */
2005-12-11 16:14:44 +08:00
internal_file = estrndup ( internal_file ,
strlen ( internal_file ) ) ;
2005-12-05 04:35:38 +08:00
php_url_free ( resource ) ;
2006-01-11 09:51:47 +08:00
return phar_make_dirstream ( internal_file , & phar - > manifest TSRMLS_CC ) ;
2005-12-05 04:35:38 +08:00
}
}
2006-01-11 09:51:47 +08:00
if ( SUCCESS ! = zend_hash_move_forward ( & phar - > manifest ) ) {
2005-12-11 16:14:44 +08:00
break ;
}
2005-12-05 04:35:38 +08:00
}
}
}
php_url_free ( resource ) ;
return NULL ;
}
2006-01-03 23:59:07 +08:00
/* }}} */
2006-01-03 23:50:46 +08:00
2006-02-28 09:36:30 +08:00
/* {{{ proto void Phar::__construct(string fname [, int flags [, string alias]])
2006-03-04 10:12:22 +08:00
* Construct a Phar archive object
2006-02-28 09:36:30 +08:00
*/
PHP_METHOD ( Phar , __construct )
{
char * fname , * alias = NULL ;
int fname_len , alias_len = 0 ;
long flags = 0 ;
2006-03-04 10:12:22 +08:00
phar_archive_object * phar_obj ;
phar_archive_data * phar_data ;
2006-02-28 09:36:30 +08:00
zval * zobj = getThis ( ) , arg1 , arg2 ;
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " s|ls " , & fname , & fname_len , & flags , & alias , & alias_len ) = = FAILURE ) {
return ;
}
2006-03-04 10:12:22 +08:00
phar_obj = ( phar_archive_object * ) zend_object_store_get_object ( getThis ( ) TSRMLS_CC ) ;
2006-02-28 09:36:30 +08:00
2006-03-04 10:12:22 +08:00
if ( phar_obj - > arc . archive ) {
2006-02-28 09:36:30 +08:00
zend_throw_exception_ex ( spl_ce_BadMethodCallException , 0 TSRMLS_CC , " Cannot call constructor twice " ) ;
return ;
}
if ( phar_open_filename ( fname , fname_len , alias , alias_len , & phar_data TSRMLS_CC ) = = FAILURE ) {
zend_throw_exception_ex ( spl_ce_UnexpectedValueException , 0 TSRMLS_CC ,
" Cannot open phar file '%s' with alias '%s' " , fname , alias ) ;
return ;
}
2006-03-08 08:56:31 +08:00
phar_data - > refcount + + ;
2006-03-04 10:12:22 +08:00
phar_obj - > arc . archive = phar_data ;
2006-03-09 04:31:23 +08:00
phar_obj - > spl . oth_handler = & phar_spl_foreign_handler ;
2006-02-28 09:36:30 +08:00
fname_len = spprintf ( & fname , 0 , " phar://%s " , fname ) ;
INIT_PZVAL ( & arg1 ) ;
ZVAL_STRINGL ( & arg1 , fname , fname_len , 0 ) ;
if ( ZEND_NUM_ARGS ( ) > 1 ) {
INIT_PZVAL ( & arg2 ) ;
ZVAL_LONG ( & arg2 , flags ) ;
zend_call_method_with_2_params ( & zobj , Z_OBJCE_P ( zobj ) ,
& spl_ce_RecursiveDirectoryIterator - > constructor , " __construct " , NULL , & arg1 , & arg2 ) ;
} else {
zend_call_method_with_1_params ( & zobj , Z_OBJCE_P ( zobj ) ,
& spl_ce_RecursiveDirectoryIterator - > constructor , " __construct " , NULL , & arg1 ) ;
}
phar_obj - > spl . info_class = phar_ce_entry ;
efree ( fname ) ;
}
/* }}} */
2006-03-04 10:12:22 +08:00
# define PHAR_ARCHIVE_OBJECT() \
phar_archive_object * phar_obj = ( phar_archive_object * ) zend_object_store_get_object ( getThis ( ) TSRMLS_CC ) ; \
if ( ! phar_obj - > arc . archive ) { \
2006-02-28 09:36:30 +08:00
zend_throw_exception_ex ( spl_ce_BadMethodCallException , 0 TSRMLS_CC , \
" Cannot call method on an uninitialzed Phar object " ) ; \
return ; \
}
/* {{{ proto int Phar::count()
2006-03-04 10:12:22 +08:00
* Returns the number of entries in the Phar archive
2006-02-28 09:36:30 +08:00
*/
PHP_METHOD ( Phar , count )
{
2006-03-04 10:12:22 +08:00
PHAR_ARCHIVE_OBJECT ( ) ;
2006-02-28 09:36:30 +08:00
2006-03-04 10:12:22 +08:00
RETURN_LONG ( zend_hash_num_elements ( & phar_obj - > arc . archive - > manifest ) ) ;
2006-02-28 09:36:30 +08:00
}
/* }}} */
/* {{{ proto string Phar::getVersion()
2006-03-04 10:12:22 +08:00
* Return version info of Phar archive
2006-02-28 09:36:30 +08:00
*/
PHP_METHOD ( Phar , getVersion )
{
2006-03-04 10:12:22 +08:00
PHAR_ARCHIVE_OBJECT ( ) ;
2006-02-28 09:36:30 +08:00
2006-03-04 10:12:22 +08:00
RETURN_STRING ( phar_obj - > arc . archive - > version , 1 ) ;
2006-02-28 09:36:30 +08:00
}
/* }}} */
2006-03-05 06:48:05 +08:00
/* {{{ proto int Phar::offsetExists(string offset)
* determines whether a file exists in the phar
*/
PHP_METHOD ( Phar , offsetExists )
{
char * fname ;
int fname_len ;
PHAR_ARCHIVE_OBJECT ( ) ;
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " s " , & fname , & fname_len ) = = FAILURE ) {
return ;
}
if ( zend_hash_exists ( & phar_obj - > arc . archive - > manifest , fname , ( uint ) fname_len ) ) {
RETURN_TRUE ;
} else {
RETURN_FALSE ;
}
}
/* }}} */
/* {{{ proto int Phar::offsetGet(string offset)
* get a PharFileInfo object for a specific file
*/
PHP_METHOD ( Phar , offsetGet )
{
char * fname ;
int fname_len ;
zval * zfname ;
PHAR_ARCHIVE_OBJECT ( ) ;
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " s " , & fname , & fname_len ) = = FAILURE ) {
return ;
}
if ( ! phar_get_entry_info ( phar_obj - > arc . archive , fname , fname_len TSRMLS_CC ) ) {
zend_throw_exception_ex ( spl_ce_BadMethodCallException , 0 TSRMLS_CC , " Entry %s does not exist " , fname ) ;
} else {
fname_len = spprintf ( & fname , 0 , " phar://%s/%s " , phar_obj - > arc . archive - > fname , fname ) ;
MAKE_STD_ZVAL ( zfname ) ;
ZVAL_STRINGL ( zfname , fname , fname_len , 0 ) ;
spl_instantiate_arg_ex1 ( phar_obj - > spl . file_class , & return_value , 0 , zfname TSRMLS_CC ) ;
zval_ptr_dtor ( & zfname ) ;
}
}
/* }}} */
/* {{{ proto int Phar::offsetSet(string offset, string value)
* set the contents of an internal file to those of an external file
*/
PHP_METHOD ( Phar , offsetSet )
{
zend_throw_exception_ex ( spl_ce_BadMethodCallException , 0 TSRMLS_CC , " Operation currently not supported " ) ;
}
/* }}} */
/* {{{ proto int Phar::offsetUnset()
* remove a file from a phar
*/
PHP_METHOD ( Phar , offsetUnset )
{
zend_throw_exception_ex ( spl_ce_BadMethodCallException , 0 TSRMLS_CC , " Operation currently not supported " ) ;
}
/* }}} */
2006-02-28 09:36:30 +08:00
/* {{{ proto void PharFileInfo::__construct(string entry)
* Construct a Phar entry object
*/
PHP_METHOD ( PharFileInfo , __construct )
{
char * fname , * arch , * entry ;
int fname_len , arch_len , entry_len ;
phar_entry_object * entry_obj ;
phar_entry_info * entry_info ;
2006-03-04 10:12:22 +08:00
phar_archive_data * phar_data ;
2006-02-28 09:36:30 +08:00
zval * zobj = getThis ( ) , arg1 ;
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " s " , & fname , & fname_len ) = = FAILURE ) {
return ;
}
2006-03-05 06:48:05 +08:00
2006-02-28 09:36:30 +08:00
entry_obj = ( phar_entry_object * ) zend_object_store_get_object ( getThis ( ) TSRMLS_CC ) ;
if ( entry_obj - > ent . entry ) {
zend_throw_exception_ex ( spl_ce_BadMethodCallException , 0 TSRMLS_CC , " Cannot call constructor twice " ) ;
return ;
}
if ( phar_split_fname ( fname , fname_len , & arch , & arch_len , & entry , & entry_len TSRMLS_CC ) = = FAILURE ) {
zend_throw_exception_ex ( spl_ce_UnexpectedValueException , 0 TSRMLS_CC ,
" Cannot access phar file entry '%s' " , fname ) ;
return ;
}
if ( phar_open_filename ( arch , arch_len , NULL , 0 , & phar_data TSRMLS_CC ) = = FAILURE ) {
zend_throw_exception_ex ( spl_ce_UnexpectedValueException , 0 TSRMLS_CC ,
" Cannot open phar file '%s' " , fname ) ;
return ;
}
if ( ( entry_info = phar_get_entry_info ( phar_data , entry , entry_len TSRMLS_CC ) ) = = NULL ) {
zend_throw_exception_ex ( spl_ce_UnexpectedValueException , 0 TSRMLS_CC ,
2006-03-04 10:12:22 +08:00
" Cannot access phar file entry '%s' in archive '%s' " , entry , arch ) ;
2006-02-28 09:36:30 +08:00
return ;
}
entry_obj - > ent . entry = entry_info ;
INIT_PZVAL ( & arg1 ) ;
ZVAL_STRINGL ( & arg1 , fname , fname_len , 0 ) ;
zend_call_method_with_1_params ( & zobj , Z_OBJCE_P ( zobj ) ,
& spl_ce_SplFileInfo - > constructor , " __construct " , NULL , & arg1 ) ;
}
/* }}} */
# define PHAR_ENTRY_OBJECT() \
phar_entry_object * entry_obj = ( phar_entry_object * ) zend_object_store_get_object ( getThis ( ) TSRMLS_CC ) ; \
if ( ! entry_obj - > ent . entry ) { \
zend_throw_exception_ex ( spl_ce_BadMethodCallException , 0 TSRMLS_CC , \
" Cannot call method on an uninitialzed PharFileInfo object " ) ; \
return ; \
}
/* {{{ proto int PharFileInfo::getCompressedSize()
* Returns the compressed size
*/
PHP_METHOD ( PharFileInfo , getCompressedSize )
{
PHAR_ENTRY_OBJECT ( ) ;
RETURN_LONG ( entry_obj - > ent . entry - > compressed_filesize ) ;
}
/* }}} */
/* {{{ proto int PharFileInfo::getCRC32()
* Returns CRC32 code or throws an exception if not CRC checked
*/
PHP_METHOD ( PharFileInfo , getCRC32 )
{
PHAR_ENTRY_OBJECT ( ) ;
if ( entry_obj - > ent . entry - > crc_checked ) {
RETURN_LONG ( entry_obj - > ent . entry - > crc32 ) ;
} else {
zend_throw_exception_ex ( spl_ce_BadMethodCallException , 0 TSRMLS_CC , \
" Phar entry was not CRC checked " ) ; \
}
}
/* }}} */
/* {{{ proto int PharFileInfo::getPharFlags()
* Returns the Phar file entry flags
*/
PHP_METHOD ( PharFileInfo , getPharFlags )
{
PHAR_ENTRY_OBJECT ( ) ;
RETURN_LONG ( entry_obj - > ent . entry - > flags ) ;
}
/* }}} */
/* {{{ proto int PharFileInfo::isCRCChecked()
* Returns whether file entry is CRC checked
*/
PHP_METHOD ( PharFileInfo , isCRCChecked )
{
PHAR_ENTRY_OBJECT ( ) ;
RETURN_BOOL ( entry_obj - > ent . entry - > crc_checked ) ;
}
/* }}} */
2006-01-03 23:50:46 +08:00
# ifdef COMPILE_DL_PHAR
ZEND_GET_MODULE ( phar )
# endif
/* {{{ phar_functions[]
*
* Every user visible function must have an entry in phar_functions [ ] .
*/
function_entry phar_functions [ ] = {
{ NULL , NULL , NULL } /* Must be the last line in phar_functions[] */
} ;
2006-02-28 09:36:30 +08:00
static
2006-02-28 09:57:00 +08:00
ZEND_BEGIN_ARG_INFO_EX ( arginfo_phar___construct , 0 , 0 , 1 )
2006-02-28 09:36:30 +08:00
ZEND_ARG_INFO ( 0 , fname )
2006-02-28 09:57:00 +08:00
ZEND_ARG_INFO ( 0 , flags )
ZEND_ARG_INFO ( 0 , alias )
2006-02-28 09:36:30 +08:00
ZEND_END_ARG_INFO ( ) ;
2006-01-03 23:59:07 +08:00
static
2006-02-28 09:57:00 +08:00
ZEND_BEGIN_ARG_INFO_EX ( arginfo_phar_mapPhar , 0 , 0 , 0 )
2006-01-03 23:59:07 +08:00
ZEND_ARG_INFO ( 0 , alias )
ZEND_END_ARG_INFO ( ) ;
2006-01-07 01:23:42 +08:00
static
2006-02-28 09:57:00 +08:00
ZEND_BEGIN_ARG_INFO_EX ( arginfo_phar_loadPhar , 0 , 0 , 1 )
2006-01-07 01:23:42 +08:00
ZEND_ARG_INFO ( 0 , fname )
ZEND_ARG_INFO ( 0 , alias )
ZEND_END_ARG_INFO ( ) ;
2006-03-05 06:48:05 +08:00
static
ZEND_BEGIN_ARG_INFO_EX ( arginfo_phar_offsetExists , 0 , 0 , 1 )
ZEND_ARG_INFO ( 0 , entry )
ZEND_END_ARG_INFO ( ) ;
static
ZEND_BEGIN_ARG_INFO_EX ( arginfo_phar_offsetSet , 0 , 0 , 2 )
ZEND_ARG_INFO ( 0 , entry )
ZEND_ARG_INFO ( 0 , value )
ZEND_END_ARG_INFO ( ) ;
2006-01-03 23:50:46 +08:00
zend_function_entry php_archive_methods [ ] = {
2006-02-28 09:36:30 +08:00
PHP_ME ( Phar , __construct , arginfo_phar___construct , 0 )
PHP_ME ( Phar , count , NULL , 0 )
PHP_ME ( Phar , getVersion , NULL , 0 )
2006-03-05 06:48:05 +08:00
PHP_ME ( Phar , offsetGet , arginfo_phar_offsetExists , ZEND_ACC_PUBLIC )
PHP_ME ( Phar , offsetSet , arginfo_phar_offsetSet , ZEND_ACC_PUBLIC )
PHP_ME ( Phar , offsetUnset , arginfo_phar_offsetExists , ZEND_ACC_PUBLIC )
PHP_ME ( Phar , offsetExists , arginfo_phar_offsetExists , ZEND_ACC_PUBLIC )
2006-02-28 09:36:30 +08:00
/* static member functions */
2006-01-07 01:23:42 +08:00
PHP_ME ( Phar , apiVersion , NULL , ZEND_ACC_PUBLIC | ZEND_ACC_STATIC | ZEND_ACC_FINAL )
PHP_ME ( Phar , canCompress , NULL , ZEND_ACC_PUBLIC | ZEND_ACC_STATIC | ZEND_ACC_FINAL )
PHP_ME ( Phar , mapPhar , arginfo_phar_mapPhar , ZEND_ACC_PUBLIC | ZEND_ACC_STATIC | ZEND_ACC_FINAL )
PHP_ME ( Phar , loadPhar , arginfo_phar_loadPhar , ZEND_ACC_PUBLIC | ZEND_ACC_STATIC | ZEND_ACC_FINAL )
2006-01-03 23:50:46 +08:00
{ NULL , NULL , NULL }
} ;
2006-02-28 09:36:30 +08:00
static
2006-02-28 09:57:00 +08:00
ZEND_BEGIN_ARG_INFO_EX ( arginfo_entry___construct , 0 , 0 , 1 )
2006-02-28 09:36:30 +08:00
ZEND_ARG_INFO ( 0 , fname )
2006-02-28 09:57:00 +08:00
ZEND_ARG_INFO ( 0 , flags )
2006-02-28 09:36:30 +08:00
ZEND_END_ARG_INFO ( ) ;
zend_function_entry php_entry_methods [ ] = {
PHP_ME ( PharFileInfo , __construct , arginfo_entry___construct , 0 )
PHP_ME ( PharFileInfo , getCompressedSize , NULL , 0 )
PHP_ME ( PharFileInfo , getCRC32 , NULL , 0 )
PHP_ME ( PharFileInfo , getPharFlags , NULL , 0 )
PHP_ME ( PharFileInfo , isCRCChecked , NULL , 0 )
{ NULL , NULL , NULL }
} ;
2006-01-03 23:50:46 +08:00
/* }}} */
/* {{{ php_phar_init_globals
*/
static void php_phar_init_globals_module ( zend_phar_globals * phar_globals )
{
memset ( phar_globals , 0 , sizeof ( zend_phar_globals ) ) ;
}
/* }}} */
2006-03-08 08:56:31 +08:00
PHP_MINIT_FUNCTION ( phar ) /* {{{ */
2006-01-03 23:50:46 +08:00
{
2006-02-28 09:36:30 +08:00
zend_class_entry ce ;
2006-01-03 23:50:46 +08:00
ZEND_INIT_MODULE_GLOBALS ( phar , php_phar_init_globals_module , NULL ) ;
2006-02-28 09:36:30 +08:00
INIT_CLASS_ENTRY ( ce , " Phar " , php_archive_methods ) ;
2006-03-04 10:12:22 +08:00
phar_ce_archive = zend_register_internal_class_ex ( & ce , spl_ce_RecursiveDirectoryIterator , NULL TSRMLS_CC ) ;
2006-02-28 09:36:30 +08:00
2006-03-05 06:48:05 +08:00
zend_class_implements ( phar_ce_archive TSRMLS_CC , 2 , spl_ce_Countable , zend_ce_arrayaccess ) ;
2006-02-28 09:36:30 +08:00
INIT_CLASS_ENTRY ( ce , " PharFileInfo " , php_entry_methods ) ;
phar_ce_entry = zend_register_internal_class_ex ( & ce , spl_ce_SplFileInfo , NULL TSRMLS_CC ) ;
2006-01-04 10:26:15 +08:00
2006-01-03 23:50:46 +08:00
return php_register_url_stream_wrapper ( " phar " , & php_stream_phar_wrapper TSRMLS_CC ) ;
}
/* }}} */
2006-03-08 08:56:31 +08:00
PHP_MSHUTDOWN_FUNCTION ( phar ) /* {{{ */
2006-01-03 23:50:46 +08:00
{
return php_unregister_url_stream_wrapper ( " phar " TSRMLS_CC ) ;
}
/* }}} */
2006-03-08 08:56:31 +08:00
PHP_RINIT_FUNCTION ( phar ) /* {{{ */
2006-01-03 23:50:46 +08:00
{
2006-03-04 10:12:22 +08:00
zend_hash_init ( & ( PHAR_GLOBALS - > phar_fname_map ) , sizeof ( phar_archive_data ) , zend_get_hash_value , destroy_phar_data , 0 ) ;
zend_hash_init ( & ( PHAR_GLOBALS - > phar_alias_map ) , sizeof ( phar_archive_data * ) , zend_get_hash_value , NULL , 0 ) ;
2006-01-03 23:50:46 +08:00
return SUCCESS ;
}
/* }}} */
2006-03-08 08:56:31 +08:00
PHP_RSHUTDOWN_FUNCTION ( phar ) /* {{{ */
2006-01-03 23:50:46 +08:00
{
2006-01-12 05:19:46 +08:00
zend_hash_destroy ( & ( PHAR_GLOBALS - > phar_alias_map ) ) ;
zend_hash_destroy ( & ( PHAR_GLOBALS - > phar_fname_map ) ) ;
2006-01-03 23:50:46 +08:00
return SUCCESS ;
}
/* }}} */
2006-03-08 08:56:31 +08:00
PHP_MINFO_FUNCTION ( phar ) /* {{{ */
2006-01-03 23:50:46 +08:00
{
php_info_print_table_start ( ) ;
2006-01-13 05:16:29 +08:00
php_info_print_table_header ( 2 , " Phar: PHP Archive support " , " enabled " ) ;
php_info_print_table_row ( 2 , " Phar API version " , PHAR_VERSION_STR ) ;
2006-01-03 23:50:46 +08:00
php_info_print_table_row ( 2 , " CVS revision " , " $Revision$ " ) ;
2006-01-13 05:16:29 +08:00
php_info_print_table_row ( 2 , " gzip compression " ,
2006-01-12 07:55:57 +08:00
# if HAVE_ZLIB
2006-01-03 23:50:46 +08:00
" enabled " ) ;
# else
" disabled " ) ;
2006-01-13 05:16:29 +08:00
# endif
php_info_print_table_row ( 2 , " bzip2 compression " ,
# if HAVE_BZ2
" enabled " ) ;
# else
" disabled " ) ;
2006-01-03 23:50:46 +08:00
# endif
2006-01-24 03:30:14 +08:00
php_info_print_table_row ( 1 , " Phar based on pear/PHP_Archive, original concept by Davey Shafik and fully realized by Gregory Beaver " ) ;
2006-01-03 23:50:46 +08:00
php_info_print_table_end ( ) ;
}
/* }}} */
/* {{{ phar_module_entry
*/
2006-01-13 05:16:29 +08:00
static zend_module_dep phar_deps [ ] = {
# if HAVE_ZLIB
ZEND_MOD_REQUIRED ( " zlib " )
# endif
# if HAVE_BZ2
ZEND_MOD_REQUIRED ( " bz2 " )
2006-01-03 23:50:46 +08:00
# endif
2006-02-28 09:36:30 +08:00
ZEND_MOD_REQUIRED ( " spl " )
2006-01-13 05:16:29 +08:00
{ NULL , NULL , NULL }
} ;
zend_module_entry phar_module_entry = {
STANDARD_MODULE_HEADER_EX , NULL ,
phar_deps ,
2006-01-04 10:26:15 +08:00
" Phar " ,
2006-01-03 23:50:46 +08:00
phar_functions ,
PHP_MINIT ( phar ) ,
PHP_MSHUTDOWN ( phar ) ,
PHP_RINIT ( phar ) ,
PHP_RSHUTDOWN ( phar ) ,
PHP_MINFO ( phar ) ,
2006-01-13 05:16:29 +08:00
PHAR_VERSION_STR ,
2006-01-03 23:50:46 +08:00
STANDARD_MODULE_PROPERTIES
} ;
/* }}} */
2005-12-05 04:35:38 +08:00
/*
* Local variables :
* tab - width : 4
* c - basic - offset : 4
* End :
* vim600 : noet sw = 4 ts = 4 fdm = marker
* vim < 600 : noet sw = 4 ts = 4
*/