├── .appveyor ├── build.ps1 ├── install.ps1 └── test.ps1 ├── .gitignore ├── .travis.yml ├── CREDITS ├── LICENSE ├── Makefile.frag ├── README.md ├── appveyor.yml ├── ci └── run-test.sh ├── client.h ├── config.m4 ├── config.w32 ├── examples └── README.md ├── package.xml ├── pecl-compat ├── LICENSE ├── README.md ├── compat.h └── src │ ├── misc.h │ ├── zend_hash.h │ ├── zend_resource.h │ └── zend_string.h ├── pecl-utils ├── README.md ├── src │ ├── arginfo.h │ ├── debug.c │ ├── debug.h │ ├── exceptions.h │ ├── mem.h │ ├── misc.h │ └── mutex.h ├── utils.c └── utils.h ├── php ├── phpc │ ├── parser_code.phpc │ └── tools_code.phpc └── src │ └── internal │ ├── parser │ ├── ParserInterface.php │ └── StringParser.php │ └── tools │ ├── Display.php │ └── embed.php ├── php_pcs.c ├── php_pcs.h ├── src ├── PCS_API.c ├── PCS_API.h ├── PCS_Class.c ├── PCS_Class.h ├── PCS_Info.c ├── PCS_Info.h ├── PCS_Loader.c ├── PCS_Loader.h ├── PCS_Stream.c ├── PCS_Stream.h ├── PCS_Tree.c ├── PCS_Tree.h ├── PCS_Utils.c └── PCS_Utils.h └── tests ├── autoload_001.phpt ├── autoload_002.phpt ├── basic_001.phpt ├── basic_002.phpt ├── file_info_001.phpt ├── file_info_002.phpt ├── register_001.phpt ├── stream_001.phpt ├── symbol_info_001.phpt └── symbol_info_002.phpt /.appveyor/build.ps1: -------------------------------------------------------------------------------- 1 | $ErrorActionPreference = "Stop" 2 | 3 | Set-Location 'c:\projects\pecl-pcs' 4 | 5 | $task = New-Item 'task.bat' -Force 6 | Add-Content $task "call phpize 2>&1" 7 | Add-Content $task "call configure --enable-pcs --enable-debug-pack 2>&1" 8 | Add-Content $task "nmake /nologo 2>&1" 9 | Add-Content $task "exit %errorlevel%" 10 | & "c:\build-cache\php-sdk-$env:BIN_SDK_VER\phpsdk-$env:VC-$env:ARCH.bat" -t $task 11 | if (-not $?) { 12 | throw "build failed with errorlevel $LastExitCode" 13 | } 14 | 15 | $source = '' 16 | if ($env:ARCH -eq 'x64') { 17 | $source += 'x64\' 18 | } 19 | $source += 'Release'; 20 | if ($env:TS -eq '1') { 21 | $source += '_TS' 22 | } 23 | 24 | $file = Get-Command php | Select-Object -ExpandProperty Definition 25 | $dest = (Get-Item $file).Directory.FullName 26 | 27 | Copy-Item "$source\php_pcs.dll" "$dest\ext\php_pcs.dll" 28 | 29 | $ini = New-Item "$dest\php-cli.ini" -Force 30 | Add-Content $ini "extension_dir=$dest\ext" 31 | Add-Content $ini 'extension=php_pcs.dll' 32 | -------------------------------------------------------------------------------- /.appveyor/install.ps1: -------------------------------------------------------------------------------- 1 | $ErrorActionPreference = "Stop" 2 | 3 | if (-not (Test-Path 'c:\build-cache')) { 4 | [void](New-Item 'c:\build-cache' -ItemType 'directory') 5 | } 6 | 7 | $bname = "php-sdk-$env:BIN_SDK_VER.zip" 8 | Write-Host $bname 9 | if (-not (Test-Path c:\build-cache\$bname)) { 10 | Invoke-WebRequest "https://github.com/microsoft/php-sdk-binary-tools/archive/$bname" -OutFile "c:\build-cache\$bname" 11 | } 12 | $dname0 = "php-sdk-binary-tools-php-sdk-$env:BIN_SDK_VER" 13 | $dname1 = "php-sdk-$env:BIN_SDK_VER" 14 | if (-not (Test-Path 'c:\build-cache\$dname1')) { 15 | Expand-Archive "c:\build-cache\$bname" "c:\build-cache" 16 | Move-Item "c:\build-cache\$dname0" "c:\build-cache\$dname1" 17 | } 18 | 19 | $releases = @{ 20 | '7.0' = '7.0.33'; 21 | '7.1' = '7.1.33'; 22 | } 23 | if ($releases.ContainsKey($env:PHP_VER)) { 24 | $phpversion = $releases.$env:PHP_VER; 25 | $base_url = 'http://windows.php.net/downloads/releases/archives'; 26 | } else { 27 | $releases = Invoke-WebRequest https://windows.php.net/downloads/releases/releases.json | ConvertFrom-Json 28 | $phpversion = $releases.$env:PHP_VER.version 29 | $base_url = 'http://windows.php.net/downloads/releases'; 30 | } 31 | 32 | $ts_part = '' 33 | if ($env:TS -eq '0') { 34 | $ts_part += '-nts' 35 | } 36 | 37 | $bname = "php-devel-pack-$phpversion$ts_part-Win32-$env:VC-$env:ARCH.zip" 38 | if (-not (Test-Path "c:\build-cache\$bname")) { 39 | Invoke-WebRequest "$base_url/$bname" -OutFile "c:\build-cache\$bname" 40 | } 41 | $dname0 = "php-$phpversion-devel-$env:VC-$env:ARCH" 42 | $dname1 = "php-$phpversion$ts_part-devel-$env:VC-$env:ARCH" 43 | if (-not (Test-Path "c:\build-cache\$dname1")) { 44 | Expand-Archive "c:\build-cache\$bname" "c:\build-cache" 45 | if ($dname0 -ne $dname1) { 46 | Move-Item "c:\build-cache\$dname0" "c:\build-cache\$dname1" 47 | } 48 | } 49 | $env:PATH = "c:\build-cache\$dname1;$env:PATH" 50 | 51 | $bname = "php-$phpversion$ts_part-Win32-$env:VC-$env:ARCH.zip" 52 | if (-not (Test-Path "c:\build-cache\$bname")) { 53 | Invoke-WebRequest "$base_url/$bname" -OutFile "c:\build-cache\$bname" 54 | } 55 | $dname = "php-$phpversion$ts_part-$env:VC-$env:ARCH" 56 | if (-not (Test-Path "c:\build-cache\$dname")) { 57 | Expand-Archive "c:\build-cache\$bname" "c:\build-cache\$dname" 58 | } 59 | $env:PATH = "c:\build-cache\$dname;$env:PATH" 60 | -------------------------------------------------------------------------------- /.appveyor/test.ps1: -------------------------------------------------------------------------------- 1 | $ErrorActionPreference = "Stop" 2 | 3 | Set-Location 'c:\projects\pecl-pcs' 4 | 5 | $env:TEST_PHP_EXECUTABLE = Get-Command 'php' | Select-Object -ExpandProperty 'Definition' 6 | & $env:TEST_PHP_EXECUTABLE 'run-tests.php' --show-diff tests 7 | if (-not $?) { 8 | throw "tests failed with errorlevel $LastExitCode" 9 | } 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .deps 2 | .libs 3 | Makefile 4 | Makefile.fragments 5 | Makefile.global 6 | Makefile.objects 7 | acinclude.m4 8 | aclocal.m4 9 | autom4te.cache 10 | *.la 11 | build 12 | config.guess 13 | config.h 14 | config.h.in 15 | config.h.in~ 16 | config.log 17 | config.nice 18 | config.status 19 | config.sub 20 | configure 21 | configure.in 22 | configure.ac 23 | include 24 | install-sh 25 | libtool 26 | ltmain.sh 27 | ltmain.sh.backup 28 | missing 29 | mkinstalldirs 30 | modules 31 | *.lo 32 | *.loT 33 | pcs-*.tgz 34 | run-tests.php 35 | tests/00*.diff 36 | tests/00*.exp 37 | tests/00*.log 38 | tests/00*.out 39 | tests/00*.php 40 | tests/00*.sh 41 | tests/00*.mem 42 | php.log 43 | test/php.log 44 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | os: linux 2 | dist: xenial 3 | language: php 4 | 5 | 6 | php: 7 | - 5.4 8 | - 5.5 9 | - 5.6 10 | - 7.0 11 | - 7.1 12 | - 7.2 13 | - 7.3 14 | - 7.4 15 | - nightly 16 | 17 | jobs: 18 | include: 19 | - os: linux 20 | dist: precise 21 | php: 5.3 22 | env: ENABLE_MAINTAINER_ZTS=0 ENABLE_DEBUG=0 23 | - os: linux 24 | dist: precise 25 | php: 5.3 26 | env: ENABLE_MAINTAINER_ZTS=1 ENABLE_DEBUG=1 27 | - os: linux 28 | dist: precise 29 | php: 5.3 30 | env: ENABLE_MAINTAINER_ZTS=1 ENABLE_DEBUG=1 USE_ZEND_ALLOC=0 31 | - os: linux 32 | dist: precise 33 | php: 5.4 34 | env: ENABLE_MAINTAINER_ZTS=0 ENABLE_DEBUG=0 35 | - os: linux 36 | dist: precise 37 | php: 5.4 38 | env: ENABLE_MAINTAINER_ZTS=1 ENABLE_DEBUG=1 39 | - os: linux 40 | dist: precise 41 | php: 5.4 42 | env: ENABLE_MAINTAINER_ZTS=1 ENABLE_DEBUG=1 USE_ZEND_ALLOC=0 43 | - os: linux 44 | dist: precise 45 | php: 5.5 46 | env: ENABLE_MAINTAINER_ZTS=0 ENABLE_DEBUG=0 47 | - os: linux 48 | dist: precise 49 | php: 5.5 50 | env: ENABLE_MAINTAINER_ZTS=1 ENABLE_DEBUG=1 51 | - os: linux 52 | dist: precise 53 | php: 5.5 54 | env: ENABLE_MAINTAINER_ZTS=1 ENABLE_DEBUG=1 USE_ZEND_ALLOC=0 55 | 56 | env: 57 | matrix: 58 | - ENABLE_MAINTAINER_ZTS=0 ENABLE_DEBUG=0 59 | - ENABLE_MAINTAINER_ZTS=1 ENABLE_DEBUG=1 60 | - ENABLE_MAINTAINER_ZTS=1 ENABLE_DEBUG=1 USE_ZEND_ALLOC=0 61 | 62 | before_install: 63 | - sudo apt-get update -qq 64 | - sudo apt-get install -y --force-yes valgrind 65 | 66 | script: sh ci/run-test.sh 67 | -------------------------------------------------------------------------------- /CREDITS: -------------------------------------------------------------------------------- 1 | pcs 2 | Francois Laupretre 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------- 2 | The PHP License, version 3.01 3 | Copyright (c) 1999 - 2005 The PHP Group. All rights reserved. 4 | -------------------------------------------------------------------- 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, is permitted provided that the following conditions 8 | are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in 15 | the documentation and/or other materials provided with the 16 | distribution. 17 | 18 | 3. The name "PHP" must not be used to endorse or promote products 19 | derived from this software without prior written permission. For 20 | written permission, please contact group@php.net. 21 | 22 | 4. Products derived from this software may not be called "PHP", nor 23 | may "PHP" appear in their name, without prior written permission 24 | from group@php.net. You may indicate that your software works in 25 | conjunction with PHP by saying "Foo for PHP" instead of calling 26 | it "PHP Foo" or "phpfoo" 27 | 28 | 5. The PHP Group may publish revised and/or new versions of the 29 | license from time to time. Each version will be given a 30 | distinguishing version number. 31 | Once covered code has been published under a particular version 32 | of the license, you may always continue to use it under the terms 33 | of that version. You may also choose to use such covered code 34 | under the terms of any subsequent version of the license 35 | published by the PHP Group. No one other than the PHP Group has 36 | the right to modify the terms applicable to covered code created 37 | under this License. 38 | 39 | 6. Redistributions of any form whatsoever must retain the following 40 | acknowledgment: 41 | "This product includes PHP software, freely available from 42 | ". 43 | 44 | THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND 45 | ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 46 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 47 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP 48 | DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 49 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 50 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 51 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 52 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 53 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 54 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 55 | OF THE POSSIBILITY OF SUCH DAMAGE. 56 | 57 | -------------------------------------------------------------------- 58 | 59 | This software consists of voluntary contributions made by many 60 | individuals on behalf of the PHP Group. 61 | 62 | The PHP Group can be contacted via Email at group@php.net. 63 | 64 | For more information on the PHP Group and the PHP project, 65 | please see . 66 | 67 | PHP includes the Zend Engine, freely available at 68 | . 69 | -------------------------------------------------------------------------------- /Makefile.frag: -------------------------------------------------------------------------------- 1 | 2 | # Files generated by Windows build 3 | 4 | WIN_CLEANUP = config.nice.bat Release_TS configure.bat configure.js 5 | 6 | PHPC_EMBED = $(srcdir)/php/src/internal/tools/embed.php 7 | 8 | .PHONY: phpc parser_code tools_code 9 | 10 | phpc: parser_code tools_code 11 | 12 | parser_code: 13 | $(PHP_EXECUTABLE) $(PHPC_EMBED) $(srcdir)/php/src/internal/parser \ 14 | parser_code $(srcdir)/php/phpc/$@.phpc 15 | 16 | tools_code: 17 | $(PHP_EXECUTABLE) $(PHPC_EMBED) $(srcdir)/php/src/internal/tools \ 18 | tools_code $(srcdir)/php/phpc/$@.phpc 19 | 20 | cleanup: clean 21 | phpize --clean 22 | @rm -rf $(WIN_CLEANUP) include modules 23 | 24 | fulltest: 25 | sh ci/run-test.sh 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/flaupretre/pecl-pcs.svg?branch=master)](https://travis-ci.org/flaupretre/pecl-pcs) 2 | [![GitHub release](https://img.shields.io/github/release/flaupretre/pecl-pcs.svg)](https://pecl.php.net/package/pcs) 3 | [![License](https://img.shields.io/badge/License-PHP-blue.svg)](http://php.net/license/3_01.txt) 4 | 5 | PCS provides a fast and easy way to mix C and PHP code in your PHP extension. 6 | 7 | PHP code can be embedded in the compiled module or distributed as a separate file tree. 8 | 9 | ---- 10 | 11 | This project is a [PHP PECL extension](http://pecl.php.net/package/pcs "PHP PECL extension"). More information is available at [the project home site](http://pcs.tekwire.net). 12 | 13 | 14 | PHP version compatibility : PHP 5.3 and above, including PHP 7. 15 | 16 | Please, download the latest stable releases from [the PECL repository](https://pecl.php.net/package/pcs). 17 | 18 | This extension uses the [PECL Compatibility Library](https://github.com/flaupretre/pecl-compat). 19 | 20 | In order to run the full PCS test suite, run 'sh ci/run-test.sh' (note that it will install the PCS extension in your PHP environment). 21 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: "{branch}.build.{build}" 2 | skip_tags: true 3 | 4 | branches: 5 | only: 6 | - develop 7 | 8 | clone_folder: c:\projects\pecl-pcs 9 | 10 | install: 11 | ps: .appveyor\install.ps1 12 | 13 | cache: 14 | c:\build-cache -> appveyor.yml, .appveyor\install.ps1 15 | 16 | environment: 17 | BIN_SDK_VER: 2.2.0 18 | matrix: 19 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 20 | ARCH: x64 21 | VC: vc14 22 | PHP_VER: 7.0 23 | TS: 0 24 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 25 | ARCH: x64 26 | VC: vc14 27 | PHP_VER: 7.1 28 | TS: 0 29 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 30 | ARCH: x64 31 | VC: vc15 32 | PHP_VER: 7.2 33 | TS: 0 34 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 35 | ARCH: x64 36 | VC: vc15 37 | PHP_VER: 7.2 38 | TS: 1 39 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 40 | ARCH: x86 41 | VC: vc15 42 | PHP_VER: 7.2 43 | TS: 0 44 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 45 | ARCH: x86 46 | VC: vc15 47 | PHP_VER: 7.2 48 | TS: 1 49 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 50 | ARCH: x64 51 | VC: vc15 52 | PHP_VER: 7.3 53 | TS: 0 54 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 55 | ARCH: x64 56 | VC: vc15 57 | PHP_VER: 7.3 58 | TS: 1 59 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 60 | ARCH: x86 61 | VC: vc15 62 | PHP_VER: 7.3 63 | TS: 0 64 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 65 | ARCH: x86 66 | VC: vc15 67 | PHP_VER: 7.3 68 | TS: 1 69 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 70 | ARCH: x64 71 | VC: vc15 72 | PHP_VER: 7.4 73 | TS: 0 74 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 75 | ARCH: x64 76 | VC: vc15 77 | PHP_VER: 7.4 78 | TS: 1 79 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 80 | ARCH: x86 81 | VC: vc15 82 | PHP_VER: 7.4 83 | TS: 0 84 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 85 | ARCH: x86 86 | VC: vc15 87 | PHP_VER: 7.4 88 | TS: 1 89 | 90 | build_script: 91 | ps: .appveyor\build.ps1 92 | 93 | test_script: 94 | ps: .appveyor\test.ps1 95 | -------------------------------------------------------------------------------- /ci/run-test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Run PCS tests 3 | # 4 | # This script can be run : 5 | # - Manually, from the PCS source dir 6 | # - By Travis-ci 7 | # - By Jenkins 8 | # 9 | # Tests we run here include : 10 | # - the PCS base tests, 11 | # - those from pcs-example if available on the local host, 12 | # - and those from the pcs-test extension (download if not present). 13 | #============================================================================= 14 | 15 | #set -x 16 | set -e # Exit on non-zero status 17 | 18 | #----- 19 | 20 | run_tests() 21 | { 22 | _ret=0 23 | 24 | echo 25 | echo "==== Running tests in $PWD" 26 | echo 27 | 28 | echo "--- Configuring ---" 29 | phpize || return 1 30 | ./configure --quiet || return 1 31 | echo "--- Rebuilding phpc files ---" 32 | make phpc || return 1 33 | echo "--- Compiling ---" 34 | make -k clean all CFLAGS='-g -Wall -Werror' || return 1 35 | 36 | dlname=`cat modules/*.la | grep dlname= | sed 's/^.*=//' | tr -d "'"` 37 | make_opts="-d extension=$dlname" 38 | [ "X$dlname" = 'Xpcs.so' ] || make_opts="-d extension=pcs $make_opts" 39 | if [ ! -f modules/pcs.so ] ; then 40 | for i in ../modules ../pecl-pcs/modules ; do 41 | if [ -f $i/pcs.so ] ; then 42 | ln -s ../$i/pcs.so modules 43 | break 44 | fi 45 | done 46 | fi 47 | 48 | # -m : test using valgrind 49 | # -q : No interaction 50 | 51 | TEST_PHP_ARGS='-q' 52 | if [ "$USE_VALGRIND" = true ] ; then 53 | TEST_PHP_ARGS="-m $TEST_PHP_ARGS" 54 | 55 | # Fix incompatibility between some versions of run-test.php and valgrind 3.7 56 | if [ "`valgrind --version`" = 'valgrind-3.7.0' ] ; then 57 | sed 's/--vex-iropt-register-updates=allregs-at-mem-access/--vex-iropt-precise-memory-exns=yes/g' r 58 | rm -f run-tests.php 59 | cp r run-tests.php 60 | fi 61 | fi 62 | export TEST_PHP_ARGS 63 | 64 | echo "--- Running tests ---" 65 | REPORT_EXIT_STATUS=1 make test PHP_TEST_SHARED_EXTENSIONS="$make_opts" || _ret=1 66 | 67 | for i in tests/*.diff tests/*.mem 68 | do 69 | [ -f "$i" ] || continue 70 | _ret=1 71 | echo 72 | echo "----------------------------" 73 | echo "$i" 74 | echo "----------------------------" 75 | cat $i 76 | done 77 | 78 | return $_ret 79 | } 80 | 81 | #--------------------------------------------------------------------------- 82 | 83 | jk_sync_tree() 84 | { 85 | # $1 = subdir 86 | 87 | rsync -a --delete --exclude .git "$SOURCE_BASE/$1/" . 88 | 89 | [ -f Makefile ] && make clean 90 | [ -f configure ] && phpize --clean 91 | } 92 | 93 | #--------------------------------------------------------------------------- 94 | #-- Run tests from another directory 95 | # On travis, clone tree 96 | 97 | run_subdir_tests() 98 | { 99 | subdir="$1" 100 | wsdir="$WS_BASE/$subdir" 101 | 102 | [ -d $wsdir ] || mkdir -p $wsdir 103 | cd $wsdir 104 | 105 | case $RUNTYPE in 106 | jenkins) 107 | jk_sync_tree $subdir 108 | ;; 109 | travis) 110 | echo "---- Cloning $subdir" 111 | git clone --depth 20 https://github.com/flaupretre/$subdir . 112 | ;; 113 | esac 114 | 115 | run_tests 116 | } 117 | 118 | #--------------------------------------------------------------------------- 119 | 120 | RUNTYPE=local 121 | [ -n "$TRAVIS" ] && RUNTYPE=travis 122 | [ -n "$JENKINS_HOME" ] && RUNTYPE=jenkins 123 | 124 | # When vagrind issues are fixed, uncomment the line below. 125 | # Valgrind (memcheck) must be on by default. 126 | #[ -z "$USE_VALGRIND" ] && USE_VALGRIND=true 127 | 128 | WS_BASE=`pwd` 129 | [ $RUNTYPE = local ] && WS_BASE="`dirname $WS_BASE`" 130 | 131 | ret=0 132 | 133 | export RUNTYPE USE_VALGRIND WS_BASE 134 | 135 | # Environment-specific initialization 136 | 137 | case $RUNTYPE in 138 | jenkins) 139 | # Choose PHP install to use 140 | phpbin=$JK_PHP_BASE$JK_PHP_VERSION/bin 141 | if [ ! -x $phpbin/phpize ] ; then 142 | echo "**ERROR: Cannot find phpize script in '$phpbin'" 143 | exit 1 144 | fi 145 | PATH=$phpbin:$PATH 146 | export PATH 147 | 148 | # Check workspace dir (security) 149 | echo "$WS_BASE" | grep /var/lib/jenkins/workspace >/dev/null 2>&1 150 | if [ $? != 0 ] ; then 151 | echo "**ERROR: Jenkins workspace error" 152 | exit 1 153 | fi 154 | 155 | [ -z "$SOURCE_BASE" ] && SOURCE_BASE=/proj/pcs/public 156 | export SOURCE_BASE 157 | ;; 158 | 159 | travis) 160 | # Xdebug versions < 2.3.3 causes PHP to crash when enabled with PCS ext (see 161 | # http://bugs.xdebug.org/view.php?id=1151). 162 | # **TODO: To be confirmed on PCS 163 | # Note that xdebug is not pre-installed on every PHP version (so, phpenv may fail) 164 | 165 | phpenv config-rm xdebug.ini || : 166 | ;; 167 | esac 168 | 169 | #=========================================================================== 170 | #-- Run base tests 171 | 172 | run_subdir_tests pecl-pcs || ret=$? 173 | 174 | #echo "--- Installing the PCS extension ---" 175 | #make install 176 | 177 | #-- Run tests from pcs-example and pcs-test 178 | 179 | run_subdir_tests pcs-example || ret=$? 180 | 181 | run_subdir_tests pcs-test || ret=$? 182 | 183 | #---- 184 | 185 | if [ "$ret" = 0 ] ;then 186 | echo "======== SUCCESS =============" 187 | else 188 | echo "************ One or more errors were encoutered **************" 189 | fi 190 | 191 | exit $ret 192 | -------------------------------------------------------------------------------- /client.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PCS extension | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2015 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt. | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Author: Francois Laupretre | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | /* Note: please keep this API compatible with PHP 5 and 7 */ 19 | 20 | #ifndef __PCS_CLIENT_H 21 | #define __PCS_CLIENT_H 22 | 23 | #include 24 | 25 | #include "zend.h" 26 | #include "zend_types.h" 27 | 28 | typedef zend_ulong PCS_ID; 29 | 30 | /* The structure contained in '.phpc' files */ 31 | 32 | typedef struct { 33 | int version; /* Descriptor version (current: 0) */ 34 | char *data; /* File contents */ 35 | size_t data_len; 36 | char *path; /* Virtual path (no leading/trailing '/') */ 37 | size_t path_len; 38 | } PCS_DESCRIPTOR; 39 | 40 | /*============================================================================*/ 41 | 42 | /*-- Flags --*/ 43 | 44 | #define PCS_LOAD_MASK 0x03 45 | 46 | /* The way the script will be loaded */ 47 | /* Default (0) = auto : 48 | - Script containing classes only -> AUTOLOAD 49 | - Script containing at least one function/constant declaration -> RINIT 50 | - Script containing no symbol or non-script -> NONE 51 | A files is recognized as a PHP script if its content starts with ' 2 | 9 | pcs 10 | pecl.php.net 11 | PHP Code Service 12 | 13 | PCS provides a fast and easy way to mix C and PHP code in your PHP extension. 14 | 15 | PHP code can be embedded in the compiled module or distributed as a separate file tree. 16 | 17 | Compatibility : PHP 5 (5.3+) and 7 18 | 19 | 20 | Francois Laupretre 21 | francois 22 | francois@php.net 23 | yes 24 | 25 | 2020-06-14 26 | 27 | 28 | 1.3.7 29 | 1.2.0 30 | 31 | 32 | beta 33 | beta 34 | 35 | PHP License 36 | 37 | * Fix Travis Ci failures 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 5.3.0 133 | 134 | 135 | 1.4.0b1 136 | 137 | 138 | 139 | pcs 140 | 141 | 142 | 143 | 144 | 1.3.7 145 | 1.2.0 146 | 147 | 148 | beta 149 | beta 150 | 151 | 2020/06/14 152 | PHP License 153 | 154 | * AppVeyor CI integration 155 | 156 | 157 | 158 | 159 | 1.3.6 160 | 1.2.0 161 | 162 | 163 | beta 164 | beta 165 | 166 | 2020/06/14 167 | PHP License 168 | 169 | * Fix Travis CI issues 170 | 171 | 172 | 173 | 174 | 1.3.5 175 | 1.2.0 176 | 177 | 178 | beta 179 | beta 180 | 181 | 2020/06/13 182 | PHP License 183 | 184 | * Fix remaining issues for PHP 7.4 185 | 186 | 187 | 188 | 189 | 1.3.4 190 | 1.2.0 191 | 192 | 193 | beta 194 | beta 195 | 196 | 2020/06/13 197 | PHP License 198 | 199 | * Fix issue #12: Fails to install in PHP 7.4.6 200 | 201 | 202 | 203 | 204 | 1.3.3 205 | 1.2.0 206 | 207 | 208 | beta 209 | beta 210 | 211 | 2017-01-20 212 | PHP License 213 | 214 | * Fix issue #8 : 1.3.2 missing file in archive 215 | * Fix compile warning in PHP 5.x 216 | 217 | 218 | 219 | 220 | 1.3.2 221 | 1.2.0 222 | 223 | 224 | beta 225 | beta 226 | 227 | 2017-01-19 228 | PHP License 229 | 230 | - Fix issue #6 : pcs breaks spl_autoload_* function 231 | 232 | 233 | 234 | 235 | 1.3.1 236 | 1.2.0 237 | 238 | 239 | beta 240 | beta 241 | 242 | 2015-12-16 243 | PHP License 244 | 245 | - Fix issue #4 : Incompatibility with suhosin (seg fault) 246 | - Fix issue #5 : User code can override PCS scripts (autoload order) 247 | 248 | 249 | 250 | 251 | 1.3.0 252 | 1.2.0 253 | 254 | 255 | beta 256 | beta 257 | 258 | 2015-12-05 259 | PHP License 260 | 261 | - Take example/test client extensions out of the tree (to fix install via the 'pecl' CLI command) 262 | - Adapt travis-ci build script 263 | 264 | 265 | 266 | 267 | 1.2.1 268 | 1.2.0 269 | 270 | 271 | beta 272 | beta 273 | 274 | 2015-12-02 275 | PHP License 276 | 277 | - Remove the '-s' option in the embed converter 278 | - Add dependencies to pcre and tokenizer (thanks to R. Collet) 279 | 280 | 281 | 282 | 283 | 1.2.0 284 | 1.2.0 285 | 286 | 287 | beta 288 | beta 289 | 290 | 2015-11-29 291 | PHP License 292 | 293 | - Improve registration and load logic 294 | - Fix static compile 295 | - Add information methods: PCS\Mgr::fileCount/fileInfos/symbolInfos 296 | - Add PCS\Display class (PHP code) to display information about virtual files and symbols as plain text or html 297 | - Add tests 298 | 299 | 300 | 301 | 302 | 1.1.1 303 | 1.0.0 304 | 305 | 306 | beta 307 | beta 308 | 309 | 2015-11-22 310 | PHP License 311 | 312 | Fixes 313 | 314 | 315 | 316 | 317 | 1.1.0 318 | 1.0.0 319 | 320 | 321 | beta 322 | beta 323 | 324 | 2015-11-19 325 | PHP License 326 | 327 | - Improve the client API 328 | - Fix Windows build 329 | 330 | 331 | 332 | 333 | 1.0.1 334 | 1.0.0 335 | 336 | 337 | beta 338 | beta 339 | 340 | 2015-11-17 341 | PHP License 342 | 343 | Improves Windows build (not functional yet) 344 | 345 | 346 | 347 | 348 | 1.0.0 349 | 1.0.0 350 | 351 | 352 | beta 353 | beta 354 | 355 | 2015-11-16 356 | PHP License 357 | 358 | First public release 359 | 360 | 361 | 362 | 363 | -------------------------------------------------------------------------------- /pecl-compat/LICENSE: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------- 2 | The PHP License, version 3.01 3 | Copyright (c) 1999 - 2016 The PHP Group. All rights reserved. 4 | -------------------------------------------------------------------- 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, is permitted provided that the following conditions 8 | are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in 15 | the documentation and/or other materials provided with the 16 | distribution. 17 | 18 | 3. The name "PHP" must not be used to endorse or promote products 19 | derived from this software without prior written permission. For 20 | written permission, please contact group@php.net. 21 | 22 | 4. Products derived from this software may not be called "PHP", nor 23 | may "PHP" appear in their name, without prior written permission 24 | from group@php.net. You may indicate that your software works in 25 | conjunction with PHP by saying "Foo for PHP" instead of calling 26 | it "PHP Foo" or "phpfoo" 27 | 28 | 5. The PHP Group may publish revised and/or new versions of the 29 | license from time to time. Each version will be given a 30 | distinguishing version number. 31 | Once covered code has been published under a particular version 32 | of the license, you may always continue to use it under the terms 33 | of that version. You may also choose to use such covered code 34 | under the terms of any subsequent version of the license 35 | published by the PHP Group. No one other than the PHP Group has 36 | the right to modify the terms applicable to covered code created 37 | under this License. 38 | 39 | 6. Redistributions of any form whatsoever must retain the following 40 | acknowledgment: 41 | "This product includes PHP software, freely available from 42 | ". 43 | 44 | THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND 45 | ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 46 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 47 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP 48 | DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 49 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 50 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 51 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 52 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 53 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 54 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 55 | OF THE POSSIBILITY OF SUCH DAMAGE. 56 | 57 | -------------------------------------------------------------------- 58 | 59 | This software consists of voluntary contributions made by many 60 | individuals on behalf of the PHP Group. 61 | 62 | The PHP Group can be contacted via Email at group@php.net. 63 | 64 | For more information on the PHP Group and the PHP project, 65 | please see . 66 | 67 | PHP includes the Zend Engine, freely available at 68 | . 69 | -------------------------------------------------------------------------------- /pecl-compat/README.md: -------------------------------------------------------------------------------- 1 | The PECL compatibility library is a set of C include files whose objective is to minimize the pain of making a PHP extension compatible with PHP 5 and 7. 2 | 3 | Project home : [https://github.com/flaupretre/pecl-compat](https://github.com/flaupretre/pecl-compat) 4 | 5 | # Main features 6 | 7 | - A set of miscellaneous compatibility macros, 8 | 9 | - A backport of the *zend_string* functions and macros to PHP 5, 10 | 11 | - A backport of most PHP 7 *zend_hash* features to PHP 5. 12 | 13 | - A compatibility library for simple resource handling 14 | 15 | # Examples 16 | 17 | For examples of using this library, look at the [PCS extension](https://github.com/flaupretre/pecl-pcs). There, you will see usage examples of most *pecl-compat* features. 18 | 19 | # Usage 20 | 21 | Using the library is simple. Download the latest release from the [github repository](https://github.com/flaupretre/pecl-compat/releases) and insert it a new subdirectory inside your code tree. Then, include the 'compat.h' file in every '.c' source file. 22 | 23 | # History 24 | 25 | I first tried to port the [PHK](http://pecl.php.net/package/phk) extension to PHP 7 using raw '#ifdef' directives. Unfortunately, it quickly became clear that it was not possible without making the code totally unreadable. For pure 'bridge' extensions, it may be possible. But, as soon as you make use of hash tables and strings, your code quicly becomes very hard to maintain. 26 | 27 | Then, I explored other solutions : separate branches, duplicate code trees... without finding one I would be satisfied with, mostly because all these solutions bring their own set of maintainability issues : separate branches bring a huge versioning problem, and separate code trees are a maintenance headache in the long term. As PHP 5 modules will probably need to be maintained during years, none of these solutions looked convincing to me. 28 | 29 | So, I reverted to the solution of keeping a single source tree and move most of my conditional code to a reusable compatibility layer. In order to benefit of the PHP 7 performance increase, most pecl-compat features are PHP 7 features backported to PHP 5. PHP 7 generally calls the underlying PHP functions directly, with the same performance as a pure-PHP7 development. So, when adapting your extension to use pecl-compat, you will, at the same time, change your code to use new PHP 7 features and make it compatible with both PHP 5 & 7. As a side effect, this makes it easier to discard PHP 5 compatibility in the future, when time has come. 30 | 31 | # Supported PHP versions 32 | 33 | 5.3 and above. 34 | -------------------------------------------------------------------------------- /pecl-compat/compat.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | Compatibility macros for different PHP versions | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2015 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt. | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Author: Francois Laupretre | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifndef _COMPAT_H 20 | #define _COMPAT_H 21 | 22 | #define PECL_COMPAT_VERSION 1.2 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include "php.h" 29 | #include "zend.h" 30 | #include "zend_extensions.h" 31 | #include "zend_API.h" 32 | 33 | #define PHP_5_0_X_API_NO 220040412 34 | #define PHP_5_1_X_API_NO 220051025 35 | #define PHP_5_2_X_API_NO 220060519 36 | #define PHP_5_3_X_API_NO 220090626 37 | #define PHP_5_4_X_API_NO 220100525 38 | #define PHP_5_5_X_API_NO 220121212 39 | #define PHP_5_6_X_API_NO 220131226 40 | 41 | #if PHP_MAJOR_VERSION >= 7 42 | # define PHP_7 43 | #endif 44 | 45 | #ifdef HAVE_CONFIG_H 46 | # include "config.h" 47 | #endif 48 | 49 | #if HAVE_STRING_H 50 | # include 51 | #endif 52 | 53 | #ifdef HAVE_SYS_TYPES_H 54 | # include 55 | #endif 56 | 57 | #ifdef PHP_WIN32 58 | # include "win32/time.h" 59 | #elif defined(NETWARE) 60 | # include 61 | # include 62 | #else 63 | # include 64 | #endif 65 | 66 | #ifdef HAVE_SYS_RESOURCE_H 67 | # include 68 | #endif 69 | 70 | #ifdef HAVE_STDARG_H 71 | #include 72 | #endif 73 | 74 | #ifdef HAVE_STDLIB_H 75 | # include 76 | #endif 77 | 78 | #ifdef HAVE_UNISTD_H 79 | # include 80 | #endif 81 | 82 | #ifdef HAVE_SYS_STAT_H 83 | # include 84 | #endif 85 | 86 | #ifdef PHP_WIN32 87 | #include 88 | #else 89 | #include 90 | #endif 91 | 92 | #if ZEND_EXTENSION_API_NO >= PHP_5_6_X_API_NO 93 | #include "zend_virtual_cwd.h" 94 | #else 95 | #include "TSRM/tsrm_virtual_cwd.h" 96 | #endif 97 | 98 | #ifdef PHP_7 99 | #include "Zend/zend_portability.h" 100 | #endif 101 | 102 | /*-- Include submodules */ 103 | 104 | #include "src/misc.h" 105 | #include "src/zend_string.h" 106 | #include "src/zend_hash.h" 107 | #include "src/zend_resource.h" 108 | 109 | #endif /* _COMPAT_H */ 110 | -------------------------------------------------------------------------------- /pecl-compat/src/misc.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | Compatibility between PHP versions | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2015 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt. | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Author: Francois Laupretre | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifndef __PECL_COMPAT_MISC_H 20 | #define __PECL_COMPAT_MISC_H 1 21 | 22 | #ifdef PHP_7 23 | /*============================================================================*/ 24 | 25 | typedef zend_string * OPENED_PATH_PTR; /* Type of stream opened_path argument */ 26 | typedef size_t COMPAT_ARG_SIZE_T; /* Size of string arguments */ 27 | typedef zend_long COMPAT_ARG_LONG_T; /* Type of long (integer) arguments */ 28 | 29 | #define compat_zval_ptr_dtor(zp) zval_ptr_dtor(zp) 30 | 31 | #else 32 | /*== PHP 5 ===================================================================*/ 33 | 34 | typedef char * OPENED_PATH_PTR; 35 | typedef off_t zend_off_t; 36 | typedef int COMPAT_ARG_SIZE_T; 37 | typedef long COMPAT_ARG_LONG_T; 38 | typedef long zend_long; 39 | 40 | #define compat_zval_ptr_dtor(zp) zval_dtor(zp) 41 | 42 | #endif 43 | /*============================================================================*/ 44 | 45 | #ifndef MIN 46 | # define MIN(a,b) (((a) < (b)) ? (a) : (b)) 47 | #endif 48 | 49 | #ifndef MAX 50 | # define MAX(a,b) (((a) > (b)) ? (a) : (b)) 51 | #endif 52 | 53 | /*---------------------------------------------------------------*/ 54 | /* (Taken from pcre/pcrelib/internal.h) */ 55 | /* To cope with SunOS4 and other systems that lack memmove() but have bcopy(), 56 | define a macro for memmove() if HAVE_MEMMOVE is false, provided that HAVE_BCOPY 57 | is set. Otherwise, include an emulating function for those systems that have 58 | neither (there are some non-Unix environments where this is the case). This 59 | assumes that all calls to memmove are moving strings upwards in store, 60 | which is the case in this extension. */ 61 | 62 | #if ! HAVE_MEMMOVE 63 | # ifdef memmove 64 | # undef memmove /* some systems may have a macro */ 65 | # endif 66 | # if HAVE_BCOPY 67 | # define memmove(a, b, c) bcopy(b, a, c) 68 | # else 69 | static void *my_memmove(unsigned char *dest, const unsigned char *src, 70 | size_t n) 71 | { 72 | int i; 73 | 74 | dest += n; 75 | src += n; 76 | for (i = 0; i < n; ++i) 77 | *(--dest) = *(--src); 78 | } 79 | # define memmove(a, b, c) my_memmove(a, b, c) 80 | # endif /* not HAVE_BCOPY */ 81 | #endif /* not HAVE_MEMMOVE */ 82 | 83 | #ifdef _AIX 84 | # undef PHP_SHLIB_SUFFIX 85 | # define PHP_SHLIB_SUFFIX "a" 86 | #endif 87 | 88 | #ifndef ZVAL_IS_ARRAY 89 | #define ZVAL_IS_ARRAY(zp) (Z_TYPE_P((zp))==IS_ARRAY) 90 | #endif 91 | 92 | #ifndef ZVAL_IS_STRING 93 | #define ZVAL_IS_STRING(zp) (Z_TYPE_P((zp))==IS_STRING) 94 | #endif 95 | 96 | #ifndef ZVAL_IS_LONG 97 | #define ZVAL_IS_LONG(zp) (Z_TYPE_P((zp))==IS_LONG) 98 | #endif 99 | 100 | #ifndef ZVAL_IS_BOOL 101 | #define ZVAL_IS_BOOL(zp) (Z_TYPE_P((zp))==IS_BOOL) 102 | #endif 103 | 104 | #ifndef INIT_ZVAL 105 | #define INIT_ZVAL(z) memset(&z, 0, sizeof(z)) 106 | #endif 107 | 108 | #ifndef ZVAL_UNDEF 109 | #define ZVAL_UNDEF(z) INIT_ZVAL(*(z)) 110 | #endif 111 | 112 | #ifndef MAKE_STD_ZVAL 113 | #define MAKE_STD_ZVAL(zp) { zp = emalloc(sizeof(zval)); INIT_ZVAL(*zp); } 114 | #endif 115 | 116 | #ifndef ALLOC_INIT_ZVAL 117 | #define ALLOC_INIT_ZVAL(zp) MAKE_STD_ZVAL(zp) 118 | #endif 119 | 120 | #ifndef ZEND_ASSUME 121 | #if defined(ZEND_WIN32) && !defined(__clang__) 122 | # define ZEND_ASSUME(c) __assume(c) 123 | #else 124 | # define ZEND_ASSUME(c) 125 | #endif 126 | #endif 127 | 128 | #ifndef ZEND_ASSERT 129 | #if ZEND_DEBUG 130 | # define ZEND_ASSERT(c) assert(c) 131 | #else 132 | # define ZEND_ASSERT(c) ZEND_ASSUME(c) 133 | #endif 134 | #endif 135 | 136 | #ifndef EMPTY_SWITCH_DEFAULT_CASE 137 | /* Only use this macro if you know for sure that all of the switches values 138 | are covered by its case statements */ 139 | #if ZEND_DEBUG 140 | # define EMPTY_SWITCH_DEFAULT_CASE() default: ZEND_ASSERT(0); break; 141 | #else 142 | # define EMPTY_SWITCH_DEFAULT_CASE() default: ZEND_ASSUME(0); break; 143 | #endif 144 | #endif 145 | 146 | #ifndef ZEND_IGNORE_VALUE 147 | #if defined(__GNUC__) && __GNUC__ >= 4 148 | # define ZEND_IGNORE_VALUE(x) (({ __typeof__ (x) __x = (x); (void) __x; })) 149 | #else 150 | # define ZEND_IGNORE_VALUE(x) ((void) (x)) 151 | #endif 152 | #endif 153 | 154 | #if PHP_API_VERSION >= 20100412 155 | typedef size_t PHP_ESCAPE_HTML_ENTITIES_SIZE; 156 | #else 157 | typedef int PHP_ESCAPE_HTML_ENTITIES_SIZE; 158 | #endif 159 | 160 | /* Avoid a warning when compiling stream wrapper declarations for 161 | openfile/opendir/url_stat */ 162 | 163 | #if ZEND_EXTENSION_API_NO >= PHP_5_6_X_API_NO 164 | # define COMPAT_STREAM_CONST_DECL const 165 | #else 166 | # define COMPAT_STREAM_CONST_DECL 167 | #endif 168 | 169 | #ifndef ZEND_MODULE_GLOBALS_ACCESSOR 170 | # ifdef ZTS 171 | # define ZEND_MODULE_GLOBALS_ACCESSOR(module_name, v) \ 172 | TSRMG(module_name##_globals_id, zend_##module_name##_globals *, v) 173 | # else 174 | # define ZEND_MODULE_GLOBALS_ACCESSOR(module_name, v) \ 175 | (module_name##_globals.v) 176 | # endif 177 | #endif 178 | 179 | #ifndef ZEND_MODULE_GLOBALS_BULK 180 | # ifdef ZTS 181 | # define ZEND_MODULE_GLOBALS_BULK(module_name) \ 182 | ((zend_##module_name##_globals *) \ 183 | (*((void ***) tsrm_ls))[module_name##_globals_id - 1]) 184 | # else 185 | # define ZEND_MODULE_GLOBALS_BULK(module_name) \ 186 | (&module_name##_globals) 187 | # endif 188 | #endif 189 | 190 | #ifndef ZEND_TSRMLS_CACHE_DEFINE 191 | # define ZEND_TSRMLS_CACHE_DEFINE() 192 | #endif 193 | 194 | #ifndef ZEND_TSRMLS_CACHE_UPDATE 195 | # define ZEND_TSRMLS_CACHE_UPDATE() 196 | #endif 197 | 198 | #ifndef PHP_FE_END 199 | # define PHP_FE_END { NULL, NULL, NULL } 200 | #endif 201 | 202 | #ifndef ZEND_MOD_END 203 | /* for php < 5.3.7 */ 204 | # define ZEND_MOD_END {NULL, NULL, NULL} 205 | #endif 206 | 207 | /*============================================================================*/ 208 | /* Duplicate a memory buffer */ 209 | /* Supports zero size (allocates 1 byte) */ 210 | 211 | static zend_always_inline void *_compat_dup(const void *ptr, size_t size, int persistent) 212 | { 213 | char *p; 214 | 215 | if (!ptr) return NULL; 216 | if (size) { 217 | p = pemalloc(size, persistent); 218 | memmove(p, ptr, size); 219 | } else { 220 | p = pemalloc(1,persistent); 221 | (*p) = '\0'; /* Ensures deterministic behavior */ 222 | } 223 | 224 | return p; 225 | } 226 | 227 | /*---------------------------------------------------------------*/ 228 | /* Duplicate a string and set terminating null. 229 | Input string does not have to be null-terminated */ 230 | 231 | static zend_always_inline void *_compat_dup_str(const void *ptr, size_t size, int persistent) 232 | { 233 | char *p; 234 | 235 | if (!ptr) return NULL; 236 | 237 | p = pemalloc(size + 1, persistent); 238 | if (size) memmove(p, ptr, size); 239 | p[size] = '\0'; 240 | return p; 241 | } 242 | 243 | /*-----------------------------------------------------*/ 244 | /* Fatal error - display message and abort process */ 245 | 246 | static zend_always_inline void compat_unsupported(char *msg) 247 | { 248 | php_error(E_CORE_ERROR, "This feature is not supported in this environment : %s", msg); 249 | exit(1); 250 | } 251 | 252 | /*============================================================================*/ 253 | #endif /* __PECL_COMPAT_MISC_H */ 254 | -------------------------------------------------------------------------------- /pecl-compat/src/zend_hash.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | zend_hash compatibility layer for PHP 5 & 7 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2005-2007 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt. | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Author: Francois Laupretre | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifndef _COMPAT_ZEND_HASH_H 20 | #define _COMPAT_ZEND_HASH_H 21 | 22 | #include "zend_hash.h" 23 | 24 | #ifdef PHP_7 25 | /*============================================================================*/ 26 | 27 | #define compat_zend_hash_exists(ht, key) zend_hash_exists(ht, key) 28 | 29 | #define compat_zend_hash_str_exists(ht, str, len) zend_hash_str_exists(ht, str, len) 30 | 31 | #define COMPAT_HASH_PTR(_zp) (&(Z_PTR_P(_zp))) 32 | 33 | /*---------*/ 34 | /* Changes from original version: 35 | - If numeric key, returned (zend_string *) is set to NULL. 36 | - If non null, returned zend_string must be released. 37 | */ 38 | static zend_always_inline int compat_zend_hash_get_current_key_ex(const HashTable *ht 39 | , zend_string **str_index, zend_ulong *num_index, HashPosition *pos) 40 | { 41 | int status; 42 | 43 | if (str_index) (*str_index) = NULL; 44 | status = zend_hash_get_current_key_ex(ht, str_index, num_index, pos); 45 | if (*str_index) zend_string_addref(*str_index); 46 | return status; 47 | } 48 | 49 | /*---------*/ 50 | /* Added - This function is equivalent to the PHP 5 version of 51 | zend_hash_get_current_key_ex() */ 52 | 53 | static zend_always_inline int compat_zend_hash_str_get_current_key_ex(const HashTable *ht 54 | , char **str_index, size_t *str_length, zend_ulong *num_index 55 | , zend_bool duplicate, HashPosition *pos) 56 | { 57 | int status; 58 | zend_string *zp; 59 | 60 | zp = NULL; 61 | status = zend_hash_get_current_key_ex(ht, &zp, num_index, pos); 62 | if (zp) { 63 | if (duplicate) { 64 | (*str_index) = estrndup(ZSTR_VAL(zp), ZSTR_LEN(zp)); 65 | } else { 66 | (*str_index) = ZSTR_VAL(zp); 67 | } 68 | (*str_length) = ZSTR_LEN(zp); 69 | } 70 | return status; 71 | } 72 | 73 | /*---------*/ 74 | 75 | static zend_always_inline void *compat_zend_hash_get_current_data_ptr_ex(HashTable *ht 76 | , HashPosition *pos) 77 | { 78 | zval *zp; 79 | 80 | zp = zend_hash_get_current_data_ex(ht, pos); 81 | return Z_PTR_P(zp); 82 | } 83 | 84 | #define compat_zend_hash_get_current_data_ptr(ht) \ 85 | compat_zend_hash_get_current_data_ptr_ex(ht, &(ht)->nInternalPointer) 86 | 87 | /*---------*/ 88 | 89 | static zend_always_inline void *compat_zend_hash_get_current_data_ex(HashTable *ht 90 | , HashPosition *pos) 91 | { 92 | return (void *)zend_hash_get_current_data_ex(ht, pos); 93 | } 94 | 95 | #define compat_zend_hash_get_current_data(ht) \ 96 | compat_zend_hash_get_current_data_ex(ht, &(ht)->nInternalPointer) 97 | 98 | #define compat_zend_hash_get_current_zval_ex(ht, pos) \ 99 | (zval *)compat_zend_hash_get_current_data_ex(ht, pos) 100 | 101 | #define compat_zend_hash_get_current_zval(ht) \ 102 | compat_zend_hash_get_current_zval_ex(ht, &(ht)->nInternalPointer) 103 | 104 | #else 105 | /*= PHP 5 ====================================================================*/ 106 | 107 | #ifndef HASH_KEY_NON_EXISTENT 108 | #define HASH_KEY_NON_EXISTENT HASH_KEY_NON_EXISTANT 109 | #endif 110 | 111 | #define COMPAT_HASH_PTR(_zp) (_zp) 112 | 113 | /*------------------------------------------------*/ 114 | 115 | static zend_always_inline void *zend_hash_add_ptr(HashTable *ht 116 | , zend_string *key, void *pData) 117 | { 118 | int status; 119 | 120 | status = zend_hash_quick_add(ht, ZSTR_VAL(key), (uint)(ZSTR_LEN(key) + 1) 121 | , (ulong)ZSTR_HASH(key), &pData, sizeof(void *), NULL); 122 | return (status == SUCCESS ? pData : NULL); 123 | } 124 | 125 | #define zend_hash_add_new_ptr(ht, key, pData) zend_hash_add_ptr(ht, key, pData) 126 | 127 | #define zend_hash_add_mem(ht, key, pData, size) \ 128 | zend_hash_add_ptr(ht, key, _compat_dup(pData, size, ht->persistent)) 129 | 130 | /*---------*/ 131 | 132 | static zend_always_inline void *zend_hash_str_add_ptr(HashTable *ht 133 | , const char *str, size_t len, void *pData) 134 | { 135 | int status; 136 | char *strn = _compat_dup_str(str, len, 0); 137 | 138 | status = zend_hash_add(ht, strn, len + 1, &pData, sizeof(void *), NULL); 139 | efree(strn); 140 | return (status == SUCCESS ? pData : NULL); 141 | } 142 | 143 | #define zend_hash_str_add_new_ptr(ht, str, len, pData) zend_hash_str_add_ptr(ht, str, len, pData) 144 | 145 | #define zend_hash_str_add_mem(ht, str, len, pData, size) \ 146 | zend_hash_str_add_ptr(ht, str, len, _compat_dup(pData, size, ht->persistent)) 147 | 148 | /*---------*/ 149 | 150 | static zend_always_inline void *zend_hash_index_add_ptr(HashTable *ht 151 | , zend_ulong h, void *pData) 152 | { 153 | int status; 154 | 155 | status = zend_hash_index_update(ht, (ulong)h, &pData, sizeof(void *), NULL); 156 | return (status == SUCCESS ? pData : NULL); 157 | } 158 | 159 | #define zend_hash_index_add_new_ptr(ht, h, pData) \ 160 | zend_hash_index_add_ptr(ht, h, pData) 161 | 162 | #define zend_hash_index_add_mem(ht, h, pData, size) \ 163 | zend_hash_index_add_ptr(ht, h, _compat_dup(pData, size, ht->persistent)) 164 | 165 | /*---------*/ 166 | 167 | static zend_always_inline void *zend_hash_next_index_insert_ptr(HashTable *ht 168 | , void *pData) 169 | { 170 | int status; 171 | 172 | status = zend_hash_next_index_insert(ht, &pData, sizeof(void *), NULL); 173 | return (status == SUCCESS ? pData : NULL); 174 | } 175 | 176 | #define zend_hash_next_index_insert_mem(ht, pData, size) \ 177 | zend_hash_next_index_insert_ptr(ht, _compat_dup(pData, size, ht->persistent)) 178 | 179 | /*---------*/ 180 | 181 | static zend_always_inline void *zend_hash_update_ptr(HashTable *ht 182 | , zend_string *key, void *pData) 183 | { 184 | int status; 185 | 186 | status = zend_hash_quick_update(ht, ZSTR_VAL(key), (uint)(ZSTR_LEN(key) + 1) 187 | , (ulong)ZSTR_HASH(key), &pData, sizeof(void *), NULL); 188 | return (status == SUCCESS ? pData : NULL); 189 | } 190 | 191 | #define zend_hash_update_mem(ht, key, pData, size) \ 192 | zend_hash_update_ptr(ht, key, _compat_dup(pData, size, ht->persistent)) 193 | 194 | /*---------*/ 195 | 196 | static zend_always_inline void *zend_hash_str_update_ptr(HashTable *ht 197 | , const char *str, size_t len, void *pData) 198 | { 199 | int status; 200 | char *strn = _compat_dup_str(str, len, 0); 201 | 202 | status = zend_hash_update(ht, strn, len + 1, &pData, sizeof(void *), NULL); 203 | efree(strn); 204 | return (status == SUCCESS ? pData : NULL); 205 | } 206 | 207 | #define zend_hash_str_upate_mem(ht, str, len, pData, size) \ 208 | zend_hash_str_update_ptr(ht, str, len, _compat_dup(pData, size, ht->persistent)) 209 | 210 | #define zend_hash_index_update_ptr(ht, h, pData) \ 211 | zend_hash_index_add_ptr(ht, h, pData) 212 | 213 | #define zend_hash_index_update_mem(ht, h, pData, size) \ 214 | zend_hash_index_add_mem(ht, h, pData, size) 215 | 216 | /*---------*/ 217 | 218 | static zend_always_inline void *zend_hash_find_ptr(const HashTable *ht 219 | , zend_string *key) 220 | { 221 | int status; 222 | void **p; 223 | 224 | status = zend_hash_quick_find(ht, ZSTR_VAL(key), (uint)(ZSTR_LEN(key) + 1) 225 | , (ulong)ZSTR_HASH(key), (void **)(&p)); 226 | return (status == SUCCESS ? (*p) : NULL); 227 | } 228 | 229 | /*---------*/ 230 | 231 | static zend_always_inline void *zend_hash_str_find_ptr(const HashTable *ht 232 | , const char *str, size_t len) 233 | { 234 | int status; 235 | void **p; 236 | char *strn = _compat_dup_str(str, len, 0); 237 | 238 | status = zend_hash_find(ht, strn, len + 1, (void **)(&p)); 239 | efree(strn); 240 | return (status == SUCCESS ? (*p) : NULL); 241 | } 242 | 243 | /*---------*/ 244 | 245 | static zend_always_inline void *zend_hash_index_find_ptr(const HashTable *ht 246 | , zend_ulong h) 247 | { 248 | int status; 249 | void **p; 250 | 251 | status = zend_hash_index_find(ht, h, (void **)(&p)); 252 | return (status == SUCCESS ? (*p) : NULL); 253 | } 254 | 255 | /*---------*/ 256 | 257 | static zend_always_inline zend_bool compat_zend_hash_exists(const HashTable *ht 258 | , zend_string *key) 259 | { 260 | return zend_hash_quick_exists(ht, ZSTR_VAL(key), (uint)(ZSTR_LEN(key) + 1) 261 | , (ulong)ZSTR_HASH(key)); 262 | } 263 | 264 | /*---------*/ 265 | 266 | static zend_always_inline zend_bool compat_zend_hash_str_exists(const HashTable *ht 267 | , const char *str, size_t len) 268 | { 269 | zend_bool status; 270 | char *strn = _compat_dup_str(str, len, 0); 271 | 272 | status = zend_hash_exists(ht, strn, (uint)(len + 1)); 273 | efree(strn); 274 | return status; 275 | } 276 | 277 | /*---------*/ 278 | /* Changes from original version: 279 | - Returns a zend_string 280 | - If key is a string, returned zend_string must be released. 281 | */ 282 | static zend_always_inline int compat_zend_hash_get_current_key_ex(const HashTable *ht 283 | , zend_string **str_index, zend_ulong *num_index, HashPosition *pos) 284 | { 285 | int status; 286 | char *str; 287 | uint str_length; 288 | ulong num; 289 | 290 | status = zend_hash_get_current_key_ex(ht, &str, &str_length, &num, 0, pos); 291 | if (status == HASH_KEY_IS_STRING) { 292 | (*str_index) = zend_string_init(str, str_length - 1, ht->persistent); 293 | } else if (status == HASH_KEY_IS_LONG) { 294 | (*num_index) = (zend_ulong)num; 295 | } 296 | return status; 297 | } 298 | 299 | /*---------*/ 300 | /* Diff with original : 301 | - Type casts 302 | - Return string length, without trailing null */ 303 | 304 | static zend_always_inline int compat_zend_hash_str_get_current_key_ex(const HashTable *ht 305 | , char **str_index, size_t *str_length, zend_ulong *num_index 306 | , zend_bool duplicate, HashPosition *pos) 307 | { 308 | int status; 309 | uint length; 310 | ulong num; 311 | 312 | status = zend_hash_get_current_key_ex(ht, str_index, &length, &num, duplicate, pos); 313 | if (status == HASH_KEY_IS_STRING) { 314 | (*str_length) = (size_t)(length - 1); 315 | } else if (status == HASH_KEY_IS_LONG) { 316 | (*num_index) = (zend_ulong)num; 317 | } 318 | return status; 319 | } 320 | 321 | /*---------*/ 322 | 323 | static zend_always_inline void *compat_zend_hash_get_current_data_ptr_ex(HashTable *ht 324 | , HashPosition *pos) 325 | { 326 | int status; 327 | void **p; 328 | 329 | status = zend_hash_get_current_data_ex(ht, (void **)(&p), pos); 330 | return ((status == SUCCESS) ? (*p) : NULL); 331 | } 332 | 333 | #define compat_zend_hash_get_current_data_ptr(ht) \ 334 | compat_zend_hash_get_current_data_ptr_ex(ht, NULL) 335 | 336 | /*---------*/ 337 | 338 | static zend_always_inline void *compat_zend_hash_get_current_data_ex(HashTable *ht 339 | , HashPosition *pos) 340 | { 341 | int status; 342 | void **p; 343 | 344 | status = zend_hash_get_current_data_ex(ht, (void **)(&p), pos); 345 | return ((status == SUCCESS) ? p : NULL); 346 | } 347 | 348 | #define compat_zend_hash_get_current_data(ht) \ 349 | compat_zend_hash_get_current_data_ex(ht, NULL) 350 | 351 | #define compat_zend_hash_get_current_zval_ex(ht, pos) \ 352 | *((zval **)compat_zend_hash_get_current_data_ex(ht, pos)) 353 | 354 | #define compat_zend_hash_get_current_zval(ht) \ 355 | compat_zend_hash_get_current_zval_ex(ht, NULL) 356 | 357 | /*------------------------------------------------------------*/ 358 | 359 | #define ZEND_HASH_FOREACH(_ht, indirect) do { \ 360 | HashPosition _pos; \ 361 | for (zend_hash_internal_pointer_reset_ex(_ht, &_pos) \ 362 | ;;zend_hash_move_forward_ex(_ht, &_pos)) { \ 363 | if (zend_hash_has_more_elements_ex(_ht, &_pos) != SUCCESS) break; 364 | 365 | #define ZEND_HASH_FOREACH_END() \ 366 | } \ 367 | } while (0) 368 | 369 | #define ZEND_HASH_FOREACH_PTR(_ht, _ptr) \ 370 | ZEND_HASH_FOREACH(_ht, 0); \ 371 | _ptr = compat_zend_hash_get_current_data_ptr_ex(_ht, &_pos); 372 | 373 | #define ZEND_HASH_FOREACH_NUM_KEY(_ht, _h) \ 374 | ZEND_HASH_FOREACH(_ht, 0); \ 375 | compat_zend_hash_get_current_key_ex(_ht, NULL, &_h, &_pos); 376 | 377 | #define ZEND_HASH_FOREACH_NUM_KEY_PTR(_ht, _h, _ptr) \ 378 | ZEND_HASH_FOREACH(_ht, 0); \ 379 | _ptr = compat_zend_hash_get_current_data_ptr_ex(_ht, &_pos); \ 380 | compat_zend_hash_get_current_key_ex(_ht, NULL, &_h, &_pos); 381 | 382 | /*============================================================================*/ 383 | #endif /* PHP_7 */ 384 | #endif /* _COMPAT_ZEND_HASH_H */ 385 | -------------------------------------------------------------------------------- /pecl-compat/src/zend_resource.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | Compatibility macros for different PHP versions | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2016 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt. | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Author: Adam Harvey | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifndef _COMPAT_ZEND_RESOURCE_H 20 | #define _COMPAT_ZEND_RESOURCE_H 21 | 22 | /* 23 | * The PHP 5 and PHP 7 resource APIs use the same function names for mutually 24 | * incompatible functions, which is unfortunate. A simple version of the PHP 5 25 | * macro API can be implemented on top of the PHP 7 API, but not vice versa 26 | * (since, for example, zend_register_resource() in PHP 5 also sets the zval, 27 | * which is a separate action in PHP 7). 28 | * 29 | * Instead of using preprocessor trickery to try to mangle things into a sane 30 | * API, I've implemented a minimal API that supports basic resource handling 31 | * and delegates appropriately on both versions. 32 | * 33 | * Destructors should be registered using the normal 34 | * zend_register_list_destructors() or zend_register_list_destructors_ex() 35 | * functions. The destructor function should take a "zend_resource *" (there is 36 | * an appropriate typedef in the PHP 5 section to make this work); as only a 37 | * subset of fields are available across PHP versions, this should be treated 38 | * as this struct in effect: 39 | * 40 | * typedef struct { 41 | * void *ptr; 42 | * int type; 43 | * } zend_resource; 44 | * 45 | * Accessing other fields will likely result in compilation errors and/or 46 | * segfaults. 47 | */ 48 | 49 | #include "zend_list.h" 50 | 51 | /** 52 | * Deletes the resource. 53 | * 54 | * On PHP 5, this is equivalent to zend_list_delete(Z_LVAL_P(zv)). 55 | * On PHP 7, this is equivalent to zend_list_close(Z_RES_P(zv)). 56 | * 57 | * @param zv The IS_RESOURCE zval to delete. 58 | */ 59 | static zend_always_inline void compat_zend_delete_resource(const zval *zv TSRMLS_DC); 60 | 61 | /** 62 | * Fetches the resource. 63 | * 64 | * This API does not support the default ID that's possible with the PHP 5 65 | * zend_fetch_resource() API, and will always set that value to -1. 66 | * 67 | * @param zv The IS_RESOURCE zval to fetch. 68 | * @param rsrc_type_name The type name to use in error messages. 69 | * @param rsrc_type The resource type ID. 70 | * @return A void pointer to the resource, which needs to be typecast, or NULL 71 | * on error. 72 | */ 73 | static zend_always_inline void *compat_zend_fetch_resource(zval *zv, const char *rsrc_type_name, int rsrc_type TSRMLS_DC); 74 | 75 | /** 76 | * Registers a new resource. 77 | * 78 | * @param zv The zval to set to IS_RESOURCE with the new resource value. 79 | * @param ptr A void pointer to the resource. 80 | * @param rsrc_type The resource type ID. 81 | */ 82 | static zend_always_inline void compat_zend_register_resource(zval *zv, void *ptr, int rsrc_type TSRMLS_DC); 83 | 84 | #ifdef PHP_7 85 | /*============================================================================*/ 86 | 87 | static zend_always_inline void compat_zend_delete_resource(const zval *zv TSRMLS_DC) 88 | { 89 | if (IS_RESOURCE != Z_TYPE_P(zv)) { 90 | return; 91 | } 92 | 93 | zend_list_close(Z_RES_P(zv)); 94 | } 95 | 96 | /*---------*/ 97 | 98 | static zend_always_inline void *compat_zend_fetch_resource(zval *zv, const char *rsrc_type_name, int rsrc_type TSRMLS_DC) 99 | { 100 | if (IS_RESOURCE != Z_TYPE_P(zv)) { 101 | return NULL; 102 | } 103 | 104 | return zend_fetch_resource(Z_RES_P(zv), rsrc_type_name, rsrc_type); 105 | } 106 | 107 | /*---------*/ 108 | 109 | static zend_always_inline void compat_zend_register_resource(zval *zv, void *ptr, int rsrc_type TSRMLS_DC) 110 | { 111 | ZVAL_RES(zv, zend_register_resource(ptr, rsrc_type)); 112 | } 113 | 114 | #else 115 | /*== PHP 5 ===================================================================*/ 116 | 117 | /* Used for destructors. */ 118 | typedef zend_rsrc_list_entry zend_resource; 119 | 120 | /*---------*/ 121 | 122 | static zend_always_inline void compat_zend_delete_resource(const zval *zv TSRMLS_DC) 123 | { 124 | if (IS_RESOURCE != Z_TYPE_P(zv)) { 125 | return; 126 | } 127 | 128 | zend_list_delete(Z_LVAL_P(zv)); 129 | } 130 | 131 | /*---------*/ 132 | 133 | static zend_always_inline void *compat_zend_fetch_resource(zval *zv, const char *rsrc_type_name, int rsrc_type TSRMLS_DC) 134 | { 135 | #if ZEND_MODULE_API_NO >= 20100412 136 | return zend_fetch_resource(&zv TSRMLS_CC, -1, rsrc_type_name, NULL, 1, rsrc_type); 137 | #else 138 | return zend_fetch_resource(&zv TSRMLS_CC, -1, (char *)rsrc_type_name, NULL, 1, rsrc_type); 139 | #endif 140 | } 141 | 142 | /*---------*/ 143 | 144 | static zend_always_inline void compat_zend_register_resource(zval *zv, void *ptr, int rsrc_type TSRMLS_DC) 145 | { 146 | ZEND_REGISTER_RESOURCE(zv, ptr, rsrc_type); 147 | } 148 | 149 | #endif /* PHP_7 */ 150 | /*============================================================================*/ 151 | 152 | #endif /* _COMPAT_ZEND_RESOURCE_H */ 153 | -------------------------------------------------------------------------------- /pecl-compat/src/zend_string.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | zend_string compatibility layer for PHP 5 & 7 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2005-2007 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt. | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Author: Francois Laupretre | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifndef _COMPAT_ZEND_STRING_H 20 | #define _COMPAT_ZEND_STRING_H 21 | 22 | #ifdef PHP_7 23 | /*============================================================================*/ 24 | #include "zend_string.h" 25 | 26 | #ifndef ZSTR_IS_PERSISTENT 27 | # define ZSTR_IS_PERSISTENT(s) (GC_FLAGS(s) & IS_STR_PERSISTENT) 28 | #endif 29 | 30 | #else 31 | /*============================================================================*/ 32 | /*---- zend_string for PHP 5 ----*/ 33 | 34 | struct _zend_string { 35 | int persistent; 36 | int hash_is_set; /* needed because computed hash may be null */ 37 | zend_ulong h; /* hash value */ 38 | uint32_t refcount; 39 | size_t len; 40 | char val[1]; 41 | }; 42 | 43 | typedef struct _zend_string zend_string; 44 | 45 | /* Shortcuts */ 46 | 47 | #define ZSTR_VAL(zstr) (zstr)->val 48 | #define ZSTR_LEN(zstr) (zstr)->len 49 | #define ZSTR_H(zstr) (zstr)->h 50 | #define ZSTR_HASH(zstr) zend_string_hash_val(zstr) 51 | 52 | #define _ZSTR_HEADER_SIZE XtOffsetOf(zend_string, val) 53 | #define _ZSTR_STRUCT_SIZE(len) (_ZSTR_HEADER_SIZE + len + 1) 54 | 55 | #define ZSTR_IS_PERSISTENT(s) (s->persistent) 56 | 57 | /*---------*/ 58 | 59 | static zend_always_inline uint32_t zend_string_refcount(zend_string *s) 60 | { 61 | return (s->refcount); 62 | } 63 | 64 | /*---------*/ 65 | 66 | static zend_always_inline uint32_t zend_string_addref(zend_string *s) 67 | { 68 | return ++(s->refcount); 69 | } 70 | 71 | /*---------*/ 72 | 73 | static zend_always_inline uint32_t zend_string_delref(zend_string *s) 74 | { 75 | return --(s->refcount); 76 | } 77 | 78 | /*---------*/ 79 | 80 | static zend_always_inline zend_ulong zend_string_hash_val(zend_string *s) 81 | { 82 | char c, *p; 83 | 84 | if (! s->hash_is_set) { 85 | /* Compute with terminating null but preserve string */ 86 | p = &(ZSTR_VAL(s)[ZSTR_LEN(s)]); 87 | c = (*p); 88 | (*p) = '\0'; 89 | ZSTR_H(s) = zend_get_hash_value(ZSTR_VAL(s), ZSTR_LEN(s)+1); 90 | (*p) = c; 91 | s->hash_is_set = 1; 92 | } 93 | return ZSTR_H(s); 94 | } 95 | 96 | /*---------*/ 97 | 98 | static zend_always_inline void zend_string_forget_hash_val(zend_string *s) 99 | { 100 | s->hash_is_set = 0; 101 | ZSTR_H(s) = 0; /* Security */ 102 | } 103 | 104 | /*---------*/ 105 | 106 | static zend_always_inline zend_string *zend_string_alloc(size_t len, int persistent) 107 | { 108 | zend_string *ret = (zend_string *)pemalloc(ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(len)), persistent); 109 | ret->persistent = persistent; 110 | zend_string_forget_hash_val(ret); 111 | ret->refcount = 1; 112 | ZSTR_LEN(ret) = len; 113 | return ret; 114 | } 115 | 116 | /*---------*/ 117 | 118 | static zend_always_inline zend_string *zend_string_safe_alloc(size_t n 119 | , size_t m, size_t l, int persistent) 120 | { 121 | zend_string *ret = (zend_string *)safe_pemalloc(n, m, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(l)), persistent); 122 | ret->persistent = persistent; 123 | zend_string_forget_hash_val(ret); 124 | ret->refcount = 1; 125 | ZSTR_LEN(ret) = l; 126 | return ret; 127 | } 128 | 129 | /*---------*/ 130 | 131 | static zend_always_inline zend_string *zend_string_init(const char *str, size_t len, int persistent) 132 | { 133 | zend_string *ret = zend_string_alloc(len, persistent); 134 | 135 | memcpy(ZSTR_VAL(ret), str, len); 136 | ZSTR_VAL(ret)[len] = '\0'; 137 | return ret; 138 | } 139 | 140 | /*---------*/ 141 | 142 | static zend_always_inline zend_string *zend_string_dup(zend_string *s, int persistent) 143 | { 144 | zend_string *target; 145 | 146 | target = zend_string_init(ZSTR_VAL(s), ZSTR_LEN(s), persistent); 147 | if (s->hash_is_set) { 148 | ZSTR_H(target) = ZSTR_H(s); 149 | target->hash_is_set = 1; 150 | } 151 | 152 | return target; 153 | } 154 | 155 | /*---------*/ 156 | 157 | static zend_always_inline zend_string *zend_string_realloc(zend_string *s 158 | , size_t len, int persistent) 159 | { 160 | zend_string *ret; 161 | 162 | if (EXPECTED(s->refcount == 1)) { 163 | ret = (zend_string *)perealloc(s, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(len)), persistent); 164 | ZSTR_LEN(ret) = len; 165 | zend_string_forget_hash_val(ret); 166 | return ret; 167 | } 168 | 169 | zend_string_delref(s); 170 | ret = zend_string_alloc(len, persistent); 171 | memcpy(ZSTR_VAL(ret), ZSTR_VAL(s), MIN(len, ZSTR_LEN(s)) + 1); 172 | 173 | return ret; 174 | } 175 | 176 | /*---------*/ 177 | 178 | static zend_always_inline zend_string *zend_string_extend(zend_string *s 179 | , size_t len, int persistent) 180 | { 181 | zend_string *ret; 182 | 183 | ZEND_ASSERT(len >= ZSTR_LEN(s)); 184 | 185 | if (EXPECTED(s->refcount == 1)) { 186 | ret = (zend_string *)perealloc(s, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(len)), persistent); 187 | ZSTR_LEN(ret) = len; 188 | zend_string_forget_hash_val(ret); 189 | return ret; 190 | } 191 | 192 | zend_string_delref(s); 193 | ret = zend_string_alloc(len, persistent); 194 | memcpy(ZSTR_VAL(ret), ZSTR_VAL(s), ZSTR_LEN(s) + 1); 195 | 196 | return ret; 197 | } 198 | 199 | /*---------*/ 200 | 201 | static zend_always_inline zend_string *zend_string_truncate(zend_string *s 202 | , size_t len, int persistent) 203 | { 204 | zend_string *ret; 205 | 206 | ZEND_ASSERT(len <= ZSTR_LEN(s)); 207 | 208 | if (EXPECTED(s->refcount == 1)) { 209 | ret = (zend_string *)perealloc(s, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(len)), persistent); 210 | ZSTR_LEN(ret) = len; 211 | zend_string_forget_hash_val(ret); 212 | return ret; 213 | } 214 | 215 | zend_string_delref(s); 216 | ret = zend_string_alloc(len, persistent); 217 | memcpy(ZSTR_VAL(ret), ZSTR_VAL(s), len + 1); 218 | 219 | return ret; 220 | } 221 | 222 | /*---------*/ 223 | 224 | static zend_always_inline zend_string *zend_string_safe_realloc(zend_string *s 225 | , size_t n, size_t m, size_t l, int persistent) 226 | { 227 | zend_string *ret; 228 | 229 | if (EXPECTED(s->refcount == 1)) { 230 | ret = (zend_string *)safe_perealloc(s, n, m, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(l)), persistent); 231 | ZSTR_LEN(ret) = (n * m) + l; 232 | zend_string_forget_hash_val(ret); 233 | return ret; 234 | } 235 | 236 | zend_string_delref(s); 237 | ret = zend_string_safe_alloc(n, m, l, persistent); 238 | memcpy(ZSTR_VAL(ret), ZSTR_VAL(s), MIN((n * m) + l, ZSTR_LEN(s)) + 1); 239 | return ret; 240 | } 241 | 242 | /*---------*/ 243 | 244 | static zend_always_inline void zend_string_free(zend_string *s) 245 | { 246 | if (s) { 247 | pefree(s, s->persistent); 248 | } 249 | } 250 | 251 | 252 | /*---------*/ 253 | 254 | static zend_always_inline void zend_string_release(zend_string *s) 255 | { 256 | if (s) { 257 | s->refcount--; 258 | if (s->refcount == 0) { 259 | zend_string_free(s); 260 | } 261 | } 262 | } 263 | 264 | /*---------*/ 265 | 266 | static zend_always_inline zend_string *zend_string_copy(zend_string *s) 267 | { 268 | zend_string_addref(s); 269 | return (s); 270 | } 271 | 272 | /*---------*/ 273 | 274 | static zend_always_inline zend_bool zend_string_equals(zend_string *s1, zend_string *s2) 275 | { 276 | return s1 == s2 || (s1->len == s2->len && !memcmp(s1->val, s2->val, s1->len)); 277 | } 278 | 279 | #define zend_string_equals_literal(str, literal) \ 280 | ((str)->len == sizeof(literal)-1 && !memcmp((str)->val, literal, sizeof(literal) - 1)) 281 | 282 | #endif /* PHP_7 */ 283 | #endif /* _COMPAT_ZEND_STRING_H */ 284 | -------------------------------------------------------------------------------- /pecl-utils/README.md: -------------------------------------------------------------------------------- 1 | This is a set of C functions and macros to help PHP extension developers. 2 | 3 | Home site : [https://github.com/flaupretre/pecl-utils](https://github.com/flaupretre/pecl-utils) 4 | 5 | Features include common arginfo structures, debug macros, exception macros, memory allocation, mutexes... 6 | 7 | For examples of using this library, look at the [PCS extension](https://github.com/flaupretre/pecl-pcs). 8 | 9 | Note that this code uses the [PECL compatibility library](https://github.com/flaupretre/pecl-compat), which must be included first. 10 | 11 | # Supported PHP versions 12 | 13 | 5.3 and above, including 7. 14 | 15 | -------------------------------------------------------------------------------- /pecl-utils/src/arginfo.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | Common utility function for PHP extensions | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2015 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt. | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Author: Francois Laupretre | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifndef __PECL_UTILS_ARGINFO_H 20 | #define __PECL_UTILS_ARGINFO_H 1 21 | 22 | /*============================================================================*/ 23 | 24 | ZEND_BEGIN_ARG_INFO_EX(UT_noarg_arginfo, 0, 0, 0) 25 | ZEND_END_ARG_INFO() 26 | 27 | ZEND_BEGIN_ARG_INFO_EX(UT_1arg_arginfo, 0, 0, 1) 28 | ZEND_ARG_INFO(0, arg1) 29 | ZEND_END_ARG_INFO() 30 | 31 | ZEND_BEGIN_ARG_INFO_EX(UT_2args_arginfo, 0, 0, 2) 32 | ZEND_ARG_INFO(0, arg1) 33 | ZEND_ARG_INFO(0, arg2) 34 | ZEND_END_ARG_INFO() 35 | 36 | ZEND_BEGIN_ARG_INFO_EX(UT_3args_arginfo, 0, 0, 3) 37 | ZEND_ARG_INFO(0, arg1) 38 | ZEND_ARG_INFO(0, arg2) 39 | ZEND_ARG_INFO(0, arg3) 40 | ZEND_END_ARG_INFO() 41 | 42 | /*-- Return by ref --*/ 43 | 44 | ZEND_BEGIN_ARG_INFO_EX(UT_noarg_ref_arginfo, 0, 1, 0) 45 | ZEND_END_ARG_INFO() 46 | 47 | ZEND_BEGIN_ARG_INFO_EX(UT_1arg_ref_arginfo, 0, 1, 1) 48 | ZEND_ARG_INFO(0, arg1) 49 | ZEND_END_ARG_INFO() 50 | 51 | ZEND_BEGIN_ARG_INFO_EX(UT_2args_ref_arginfo, 0, 1, 2) 52 | ZEND_ARG_INFO(0, arg1) 53 | ZEND_ARG_INFO(0, arg2) 54 | ZEND_END_ARG_INFO() 55 | 56 | ZEND_BEGIN_ARG_INFO_EX(UT_3args_ref_arginfo, 0, 1, 3) 57 | ZEND_ARG_INFO(0, arg1) 58 | ZEND_ARG_INFO(0, arg2) 59 | ZEND_ARG_INFO(0, arg3) 60 | ZEND_END_ARG_INFO() 61 | 62 | /*============================================================================*/ 63 | #endif /* __PECL_UTILS_ARGINFO_H */ 64 | -------------------------------------------------------------------------------- /pecl-utils/src/debug.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | Common utility function for PHP extensions | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2015 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt. | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Author: Francois Laupretre | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifdef UT_DEBUG 20 | /*---------------------------------------------------------------*/ 21 | 22 | #include "php.h" 23 | 24 | /*---------------------------------------------------------------*/ 25 | 26 | #ifdef HAVE_GETTIMEOFDAY 27 | static struct timeval _ut_base_tp; 28 | #endif 29 | 30 | /*------------*/ 31 | 32 | static void ut_dbg_init_time() 33 | { 34 | #ifdef HAVE_GETTIMEOFDAY 35 | struct timezone tz; 36 | 37 | (void)gettimeofday(&_ut_base_tp,&tz); 38 | #endif 39 | } 40 | 41 | /*------------*/ 42 | 43 | static void ut_dbg_print_time() 44 | { 45 | #ifdef UT_DBG_TIMESTAMPS 46 | #ifdef HAVE_GETTIMEOFDAY 47 | struct timeval tp; 48 | struct timezone tz; 49 | time_t sec; 50 | 51 | (void)gettimeofday(&tp,&tz); 52 | sec=tp.tv_sec-_ut_base_tp.tv_sec; 53 | if (ut_is_web()) php_printf("
"); 54 | php_printf("<"); 55 | if (sec) php_printf("(%ld s) ",sec); 56 | else php_printf("(%ld µs) ",(tp.tv_usec-_ut_base_tp.tv_usec)); 57 | memmove(&_ut_base_tp,&tp,sizeof(tp)); 58 | #endif 59 | #endif 60 | } 61 | 62 | #endif /* UT_DEBUG */ 63 | 64 | /*============================================================================*/ 65 | -------------------------------------------------------------------------------- /pecl-utils/src/debug.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | Common utility function for PHP extensions | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2015 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt. | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Author: Francois Laupretre | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifndef __PECL_UTILS_DEBUG_H 20 | #define __PECL_UTILS_DEBUG_H 1 21 | 22 | #ifdef PHP_WIN32 23 | #include "win32/time.h" 24 | #elif defined(NETWARE) 25 | #include 26 | #include 27 | #else 28 | #include 29 | #endif 30 | 31 | #ifdef PHP_7 32 | #include "Zend/zend_portability.h" 33 | #endif 34 | 35 | /*---------------------------------------------------------------*/ 36 | 37 | #ifdef UT_DEBUG 38 | #define DBG_INIT() ut_dbg_init_time() 39 | #define DBG_MSG(_format) { ut_dbg_print_time(); php_printf(_format "\n"); } 40 | #define DBG_MSG1(_format,_var1) { ut_dbg_print_time(); php_printf(_format "\n",_var1); } 41 | #define DBG_MSG2(_format,_var1,_var2) { ut_dbg_print_time(); php_printf(_format "\n",_var1,_var2); } 42 | #define DBG_MSG3(_format,_var1,_var2,_var3) { ut_dbg_print_time(); php_printf(_format "\n",_var1,_var2,_var3); } 43 | 44 | static void ut_dbg_init_time(); 45 | static void ut_dbg_print_time(); 46 | 47 | #else 48 | #define DBG_INIT() 49 | #define DBG_MSG(_format) 50 | #define DBG_MSG1(_format,_var1) 51 | #define DBG_MSG2(_format,_var1,_var2) 52 | #define DBG_MSG3(_format,_var1,_var2,_var3) 53 | #endif /* UT_DEBUG */ 54 | 55 | /*---------------------------------------------------------------*/ 56 | 57 | static zend_always_inline void CHECK_ZSTRING(zend_string *zsp) 58 | { 59 | ZEND_ASSERT(zsp); 60 | ZEND_ASSERT(ZSTR_VAL(zsp)[ZSTR_LEN(zsp)] == '\0'); 61 | } 62 | 63 | /*============================================================================*/ 64 | #endif /* __PECL_UTILS_DEBUG_H */ 65 | -------------------------------------------------------------------------------- /pecl-utils/src/exceptions.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | Common utility function for PHP extensions | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2015 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt. | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Author: Francois Laupretre | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifndef __PECL_UTILS_EXCEPTIONS_H 20 | #define __PECL_UTILS_EXCEPTIONS_H 1 21 | 22 | #include "zend_exceptions.h" 23 | 24 | /*============================================================================*/ 25 | 26 | #define THROW_EXCEPTION(_format) \ 27 | { \ 28 | DBG_MSG("Throwing exception: " _format); \ 29 | (void)zend_throw_exception_ex(NULL,0 TSRMLS_CC ,_format); \ 30 | } 31 | 32 | #define THROW_EXCEPTION_1(_format,_arg1) \ 33 | { \ 34 | DBG_MSG1("Throwing exception: " _format , _arg1); \ 35 | (void)zend_throw_exception_ex(NULL,0 TSRMLS_CC ,_format,_arg1); \ 36 | } 37 | 38 | #define THROW_EXCEPTION_2(_format,_arg1,_arg2) \ 39 | { \ 40 | DBG_MSG2("Throwing exception: " _format , _arg1, _arg2); \ 41 | (void)zend_throw_exception_ex(NULL,0 TSRMLS_CC ,_format,_arg1,_arg2); \ 42 | } 43 | 44 | #define THROW_EXCEPTION_3(_format,_arg1,_arg2,_arg3) \ 45 | { \ 46 | DBG_MSG3("Throwing exception: " _format , _arg1, _arg2, _arg3); \ 47 | (void)zend_throw_exception_ex(NULL,0 TSRMLS_CC ,_format,_arg1,_arg2,_arg3); \ 48 | } 49 | 50 | #define EXCEPTION_ABORT(_format) \ 51 | { \ 52 | THROW_EXCEPTION(_format); \ 53 | return; \ 54 | } 55 | 56 | #define EXCEPTION_ABORT_1(_format,_arg1) \ 57 | { \ 58 | THROW_EXCEPTION_1(_format,_arg1); \ 59 | return; \ 60 | } 61 | 62 | #define EXCEPTION_ABORT_2(_format,_arg1,_arg2) \ 63 | { \ 64 | THROW_EXCEPTION_2(_format,_arg1,_arg2); \ 65 | return; \ 66 | } 67 | 68 | #define EXCEPTION_ABORT_3(_format,_arg1,_arg2,_arg3) \ 69 | { \ 70 | THROW_EXCEPTION_3(_format,_arg1,_arg2,_arg3); \ 71 | return; \ 72 | } 73 | 74 | #define EXCEPTION_ABORT_RET(_ret,_format) \ 75 | { \ 76 | THROW_EXCEPTION(_format); \ 77 | return _ret; \ 78 | } 79 | 80 | #define EXCEPTION_ABORT_RET_1(_ret,_format,_arg1) \ 81 | { \ 82 | THROW_EXCEPTION_1(_format,_arg1); \ 83 | return _ret; \ 84 | } 85 | 86 | #define ON_EXCEPTION if (EG(exception)) 87 | 88 | #define ON_EXCEPTION_RETURN_VOID() { ON_EXCEPTION return; } 89 | 90 | #define ON_EXCEPTION_RETURN(_ret) { ON_EXCEPTION return (_ret); } 91 | 92 | /*============================================================================*/ 93 | #endif /* __PECL_UTILS_EXCEPTIONS_H */ 94 | -------------------------------------------------------------------------------- /pecl-utils/src/mem.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | Common utility function for PHP extensions | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2015 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt. | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Author: Francois Laupretre | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifndef __PECL_UTILS_MEM_H 20 | #define __PECL_UTILS_MEM_H 1 21 | 22 | #include "zend.h" 23 | #include "zend_alloc.h" 24 | 25 | /*============================================================================*/ 26 | 27 | #define ut_eallocate(ptr, size) ut_allocate(ptr, size, 0) 28 | #define ut_pallocate(ptr, size) ut_allocate(ptr, size, 1) 29 | 30 | #define PEALLOCATE(ptr, size, persistent) ptr=ut_allocate(ptr, size, persistent) 31 | #define EALLOCATE(ptr, size) PEALLOCATE(ptr, size, 0) 32 | #define PALLOCATE(ptr, size) PEALLOCATE(ptr, size, 1) 33 | #define PEFREE(ptr, persistent) PEALLOCATE(ptr, 0, persistent) 34 | #define EFREE(ptr) PEFREE(ptr, 0) 35 | #define PFREE(ptr) PEFREE(ptr, 1) 36 | 37 | #define ut_eduplicate(ptr, size) ut_duplicate(ptr, size, 0) 38 | #define ut_pduplicate(ptr, size) ut_duplicate(ptr, size, 1) 39 | 40 | /*============================================================================*/ 41 | 42 | static zend_always_inline void *ut_allocate(void *ptr, size_t size, int persistent) 43 | { 44 | if (ptr) { 45 | if (size) ptr=perealloc(ptr, size, persistent); 46 | else { 47 | pefree(ptr, persistent); 48 | ptr=NULL; 49 | } 50 | } else { 51 | if (size) ptr=pemalloc(size, persistent); 52 | } 53 | return ptr; 54 | } 55 | 56 | /*---------------------------------------------------------------*/ 57 | 58 | static zend_always_inline void *ut_duplicate(void *ptr, size_t size, int persistent) 59 | { 60 | char *p; 61 | 62 | if (!ptr) return NULL; 63 | if (size==0) return ut_allocate(NULL,1,persistent); 64 | 65 | p=ut_allocate(NULL,size,persistent); 66 | memmove(p,ptr,size); 67 | return p; 68 | } 69 | 70 | /*============================================================================*/ 71 | #endif /* __PECL_UTILS_MEM_H */ 72 | -------------------------------------------------------------------------------- /pecl-utils/src/misc.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | Common utility function for PHP extensions | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2015 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt. | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Author: Francois Laupretre | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifndef __PECL_UTILS_MISC_H 20 | #define __PECL_UTILS_MISC_H 1 21 | 22 | #include 23 | 24 | #include "main/SAPI.h" 25 | #include "zend_modules.h" 26 | 27 | /*============================================================================*/ 28 | 29 | #define CLEAR_DATA(_v) memset(&(_v),'\0',sizeof(_v)); \ 30 | 31 | #define ENSURE_LONG(zp) { if (Z_TYPE_P((zp))!=IS_LONG) convert_to_long((zp)); } 32 | #define ENSURE_BOOL(zp) { if (Z_TYPE_P((zp))!=IS_BOOL) convert_to_boolean((zp)); } 33 | #define ENSURE_STRING(zp) { if (Z_TYPE_P((zp))!=IS_STRING) convert_to_string((zp)); } 34 | 35 | #ifndef S_ISDIR 36 | # define S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR) 37 | #endif 38 | #ifndef S_ISREG 39 | # define S_ISREG(mode) (((mode)&S_IFMT) == S_IFREG) 40 | #endif 41 | 42 | #define IMM_STRL(_str) _str, sizeof(_str) - 1 43 | 44 | /* Additional status values */ 45 | 46 | #define NOT_FOUND -2 47 | 48 | /*---------------------------------------------------------------*/ 49 | 50 | static zend_always_inline int ut_is_web() 51 | { 52 | return strcmp(sapi_module.name, "cli"); 53 | } 54 | 55 | /*------------------*/ 56 | 57 | static zend_always_inline int ut_extension_loaded(char *name, int len TSRMLS_DC) 58 | { 59 | int status; 60 | 61 | status = compat_zend_hash_str_exists(&module_registry, name, len); 62 | 63 | DBG_MSG2("Checking if extension %s is loaded: %s",name,(status ? "yes" : "no")); 64 | return status; 65 | } 66 | 67 | /*-----------------------------------------------------*/ 68 | 69 | static zend_always_inline zend_module_entry *ut_getModuleData(char *name, size_t len) 70 | { 71 | zend_module_entry *module; 72 | 73 | #ifdef PHP_7 74 | zend_string *zs; 75 | 76 | zs = zend_string_init(name, len, 0); 77 | module = zend_hash_find_ptr(&module_registry, zs); 78 | zend_string_release(zs); 79 | #else 80 | int status; 81 | 82 | status = zend_hash_find(&module_registry, name, len + 1, (void **)(&module)); 83 | if (status != SUCCESS) module = NULL; 84 | #endif 85 | 86 | if (! module) { 87 | php_error(E_CORE_ERROR, "%s: Cannot retrieve module data", name); 88 | } 89 | 90 | return module; 91 | } 92 | 93 | /*-----------------------------------------------------*/ 94 | 95 | static zend_always_inline int ut_moduleIsStarted(char *name, size_t len) 96 | { 97 | zend_module_entry *module; 98 | 99 | module = ut_getModuleData(name, len); 100 | if ((! module) || (! module->module_started)) { 101 | return 0; 102 | } 103 | 104 | return 1; 105 | } 106 | 107 | /*============================================================================*/ 108 | #endif /* __PECL_UTILS_MISC_H */ 109 | -------------------------------------------------------------------------------- /pecl-utils/src/mutex.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | Common utility function for PHP extensions | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2015 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt. | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Author: Francois Laupretre | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifndef __PECL_UTILS_MUTEX_H 20 | #define __PECL_UTILS_MUTEX_H 1 21 | 22 | /*============================================================================*/ 23 | 24 | #include "TSRM/TSRM.h" 25 | 26 | /*============================================================================*/ 27 | 28 | /*-- Thread-safe stuff ------*/ 29 | 30 | #ifdef ZTS 31 | #define MutexDeclare(x) MUTEX_T x ## _mutex; 32 | #define StaticMutexDeclare(x) static MUTEX_T x ## _mutex; 33 | #define MutexSetup(x) { x ## _mutex = tsrm_mutex_alloc(); } 34 | #define MutexShutdown(x) { tsrm_mutex_free(x ## _mutex); x ## _mutex = NULL; } 35 | #define MutexLock(x) { tsrm_mutex_lock(x ## _mutex); } 36 | #define MutexUnlock(x) { tsrm_mutex_unlock(x ## _mutex); } 37 | #else 38 | #define MutexDeclare(x) 39 | #define StaticMutexDeclare(x) 40 | #define MutexSetup(x) 41 | #define MutexShutdown(x) 42 | #define MutexLock(x) 43 | #define MutexUnlock(x) 44 | #endif 45 | 46 | /*============================================================================*/ 47 | #endif /* __PECL_UTILS_MUTEX_H */ 48 | -------------------------------------------------------------------------------- /pecl-utils/utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | Common utility function for PHP extensions | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2015 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt. | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Author: Francois Laupretre | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | /*============================================================================*/ 20 | 21 | #include "src/debug.c" 22 | 23 | /*============================================================================*/ 24 | -------------------------------------------------------------------------------- /pecl-utils/utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | Common utility function for PHP extensions | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2015 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt. | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Author: Francois Laupretre | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifndef __PECL_UTILS_H 20 | #define __PECL_UTILS_H 1 21 | 22 | #define PECL_UTILS_VERSION 1.1 23 | 24 | /*============================================================================*/ 25 | 26 | #include "src/debug.h" 27 | #include "src/exceptions.h" 28 | #include "src/mem.h" 29 | #include "src/mutex.h" 30 | #include "src/misc.h" 31 | #include "src/arginfo.h" 32 | 33 | /*============================================================================*/ 34 | #endif /* __PECL_UTILS_H */ 35 | -------------------------------------------------------------------------------- /php/src/internal/parser/ParserInterface.php: -------------------------------------------------------------------------------- 1 | | 5 | +----------------------------------------------------------------------+ 6 | | Copyright (c) 2015 The PHP Group | 7 | +----------------------------------------------------------------------+ 8 | | This source file is subject to version 3.01 of the PHP license, | 9 | | that is bundled with this package in the file LICENSE, and is | 10 | | available through the world-wide-web at the following url: | 11 | | http://www.php.net/license/3_01.txt. | 12 | | If you did not receive a copy of the PHP license and are unable to | 13 | | obtain it through the world-wide-web, please send a note to | 14 | | license@php.net so we can mail you a copy immediately. | 15 | +----------------------------------------------------------------------+ 16 | | Author: Francois Laupretre | 17 | +----------------------------------------------------------------------+ 18 | */ 19 | 20 | //============================================================================= 21 | 22 | namespace PCS\Parser { 23 | 24 | interface ParserInterface 25 | { 26 | //--------------------------------- 27 | /** 28 | * Extracts symbols from input and returns them as an 29 | * array (first char is symbol type). 30 | * 31 | * @param string $buf The script to parse 32 | * @return array of symbols 33 | * @throws \Exception on parse error 34 | */ 35 | 36 | public static function parse($buf); 37 | 38 | //--- 39 | } // End of class 40 | //=========================================================================== 41 | } // End of namespace 42 | //=========================================================================== 43 | -------------------------------------------------------------------------------- /php/src/internal/parser/StringParser.php: -------------------------------------------------------------------------------- 1 | | 5 | +----------------------------------------------------------------------+ 6 | | Copyright (c) 2015 The PHP Group | 7 | +----------------------------------------------------------------------+ 8 | | This source file is subject to version 3.01 of the PHP license, | 9 | | that is bundled with this package in the file LICENSE, and is | 10 | | available through the world-wide-web at the following url: | 11 | | http://www.php.net/license/3_01.txt. | 12 | | If you did not receive a copy of the PHP license and are unable to | 13 | | obtain it through the world-wide-web, please send a note to | 14 | | license@php.net so we can mail you a copy immediately. | 15 | +----------------------------------------------------------------------+ 16 | | Author: Francois Laupretre | 17 | +----------------------------------------------------------------------+ 18 | */ 19 | 20 | //============================================================================= 21 | 22 | namespace PCS\Parser { 23 | 24 | //============================================================================= 25 | //-- For PHP version < 5.3.0 26 | 27 | // :ignore constant T_NAMESPACE 28 | if (!defined('T_NAMESPACE')) define('T_NAMESPACE',-2); 29 | // :ignore constant T_NS_SEPARATOR 30 | if (!defined('T_NS_SEPARATOR')) define('T_NS_SEPARATOR',-3); 31 | // :ignore constant T_CONST 32 | if (!defined('T_CONST')) define('T_CONST',-4); 33 | // :ignore constant T_TRAIT 34 | if (!defined('T_TRAIT')) define('T_TRAIT',-5); 35 | 36 | //=========================================================================== 37 | /** 38 | * This parser extracts symbols from a PHP script received in a string 39 | * 40 | *///========================================================================== 41 | 42 | class StringParser implements ParserInterface 43 | { 44 | //-- Symbol types 45 | 46 | const T_CLASS='L'; 47 | const T_FUNCTION='F'; 48 | const T_CONSTANT='C'; 49 | 50 | //-- Parser states : 51 | 52 | const ST_OUT=1; // Upper level 53 | const ST_FUNCTION_FOUND=self::T_FUNCTION; // Found 'function'. Looking for name 54 | const ST_SKIPPING_BLOCK_NOSTRING=3; // In block, outside of string 55 | const ST_SKIPPING_BLOCK_STRING=4; // In block, in string 56 | const ST_CLASS_FOUND=self::T_CLASS; // Found 'class'. Looking for name 57 | const ST_DEFINE_FOUND=6; // Found 'define'. Looking for '(' 58 | const ST_DEFINE_2=7; // Found '('. Looking for constant name 59 | const ST_SKIPPING_TO_EOL=8; // Got constant. Looking for EOL (';') 60 | const ST_NAMESPACE_FOUND=9; // Found 'namespace'. Looking for 61 | const ST_NAMESPACE_2=10; // Found 'namespace' and . Looking for name 62 | const ST_CONST_FOUND=11; // Found 'const'. Looking for name 63 | 64 | //--------- 65 | 66 | /** @var array(keys (<1-char symbol type>+)) */ 67 | 68 | private static $symbols = array(); 69 | 70 | /** @var array( => null) A list of symbols to exclude */ 71 | 72 | private static $exclude_list = array(); 73 | 74 | //--------------------------------------------------------------------------- 75 | 76 | private static function key($type,$name) 77 | { 78 | return $type.$name; 79 | } 80 | 81 | //--------------------------------- 82 | 83 | private static function stringToType($str) 84 | { 85 | switch($str) { 86 | case 'class': return self::T_CLASS; 87 | case 'function': return self::T_FUNCTION; 88 | case 'constant': return self::T_CONSTANT; 89 | } 90 | } 91 | 92 | //--------------------------------- 93 | 94 | private static function cleanup() 95 | { 96 | // Filter out excluded symbols 97 | if (count(self::$exclude_list)) { 98 | foreach(self::$symbols as $n => $s) { 99 | if (array_key_exists($s, self::$exclude_list)) 100 | unset(self::$symbols[$n]); 101 | } 102 | } 103 | 104 | $a=self::$symbols; 105 | self::$symbols=array(); 106 | self::$exclude_list=array(); 107 | 108 | return $a; 109 | } 110 | 111 | //--------------------------------- 112 | /** 113 | * Mark a symbol as excluded 114 | * 115 | * @param string $type one of the T_xx constants 116 | * @param string $name The symbol name 117 | * @return null 118 | */ 119 | 120 | private static function exclude($type,$name) 121 | { 122 | self::$exclude_list[self::key($type,$name)] = null; 123 | } 124 | 125 | //--------------------------------- 126 | /** 127 | * Add a symbol into the table 128 | * 129 | * Filter out the symbol from the exclude list 130 | * 131 | * @param string $type one of the T_xx constants 132 | * @param string $name The symbol name 133 | * @return null 134 | */ 135 | 136 | private static function addSymbol($type,$name) 137 | { 138 | self::$symbols[] = self::key($type, $name); 139 | } 140 | 141 | //--------------------------------- 142 | /** 143 | * Combine a namespace with a symbol 144 | * 145 | * The leading and trailing backslashes are first suppressed from the namespace. 146 | * Then, if the namespace is not empty it is prepended to the symbol using a 147 | * backslash. 148 | * 149 | * @param string $ns Namespace (can be empty) 150 | * @param string $symbol Symbol name (cannot be empty) 151 | * @return string Fully qualified name without leading backslash 152 | */ 153 | 154 | private static function combineNSSymbol($ns,$symbol) 155 | { 156 | $ns=trim($ns,'\\'); 157 | return $ns.(($ns==='') ? '' : '\\').$symbol; 158 | } 159 | 160 | //--------------------------------- 161 | /** 162 | * Register explicit declarations 163 | * 164 | * A file may disable indexing and explicitely declare symbols. 165 | * 166 | * Format: 167 | * :declare 168 | * :ignore 169 | * :ignore-file 170 | * :skip-blocks 171 | * 172 | * @return bool false if indexing is disabled on this file 173 | */ 174 | 175 | private static function parseDirectives($buf,&$skip_blocks) 176 | { 177 | $ret=true; 178 | $a=null; 179 | if (preg_match_all('{^//\s+\:(\S+)(.*)$}m',$buf,$a,PREG_SET_ORDER)!=0) { 180 | foreach($a as $match) { 181 | switch ($cmd=$match[1]) { 182 | case 'ignore-file': 183 | $ret=false; 184 | 185 | case 'skip-blocks': 186 | $skip_blocks=true; 187 | break; 188 | 189 | case 'declare': 190 | case 'ignore': 191 | $type_string=strtolower(strtok($match[2],' ')); 192 | $name=strtok(' '); 193 | if ($type_string===false || $name===false) 194 | throw new \Exception($cmd.': Directive needs 2 args'); 195 | $type=self::stringToType($type_string); 196 | if ($cmd=='declare') 197 | self::addSymbol($type,$name); 198 | else 199 | self::exclude($type,$name); 200 | break; 201 | 202 | default: 203 | throw new \Exception($cmd.': Invalid directive'); 204 | } 205 | } 206 | } 207 | return $ret; 208 | } 209 | 210 | //--------------------------------- 211 | /** 212 | * Extracts symbols from a PHP script contained in a string 213 | * 214 | * @param string $buf The script to parse 215 | * @return array of symbols 216 | * @throws \Exception on parse error 217 | */ 218 | 219 | public static function parse($buf) 220 | { 221 | $buf=str_replace("\r",'',$buf); 222 | 223 | $skip_blocks=false; 224 | 225 | if (self::parseDirectives($buf, $skip_blocks)) { 226 | self::parseTokens($buf, $skip_blocks); 227 | } 228 | 229 | return self::cleanup(); 230 | } 231 | 232 | //--------------------------------- 233 | /** 234 | * Extract symbols from script tokens 235 | */ 236 | 237 | private static function parseTokens($buf,$skip_blocks) 238 | { 239 | $block_level=0; 240 | $state=self::ST_OUT; 241 | $name=''; 242 | $ns=''; 243 | 244 | // Note: Using php_strip_whitespace() before token_get_all does not improve 245 | // performance. 246 | 247 | foreach(token_get_all($buf) as $token) { 248 | if (is_string($token)) { 249 | $tvalue=$token; 250 | $tnum=-1; 251 | $tname='String'; 252 | } else { 253 | list($tnum,$tvalue)=$token; 254 | $tname=token_name($tnum); 255 | } 256 | 257 | if (($tnum==T_COMMENT)||($tnum==T_DOC_COMMENT)) continue; 258 | if (($tnum==T_WHITESPACE)&&($state!=self::ST_NAMESPACE_FOUND)) continue; 259 | 260 | //echo "$tname <$tvalue>\n";//TRACE 261 | switch($state) { 262 | case self::ST_OUT: 263 | switch($tnum) 264 | { 265 | case T_FUNCTION: 266 | $state=self::ST_FUNCTION_FOUND; 267 | break; 268 | case T_CLASS: 269 | case T_INTERFACE: 270 | case T_TRAIT: 271 | $state=self::ST_CLASS_FOUND; 272 | break; 273 | case T_NAMESPACE: 274 | $state=self::ST_NAMESPACE_FOUND; 275 | $name=''; 276 | break; 277 | case T_CONST: 278 | $state=self::ST_CONST_FOUND; 279 | break; 280 | case T_STRING: 281 | if ($tvalue=='define') $state=self::ST_DEFINE_FOUND; 282 | $name=''; 283 | break; 284 | // If this flag is set, we skip anything enclosed 285 | // between {} chars, ignoring any conditional block. 286 | case -1: 287 | if ($tvalue=='{' && $skip_blocks) { 288 | $state=self::ST_SKIPPING_BLOCK_NOSTRING; 289 | $block_level=1; 290 | } 291 | break; 292 | } 293 | break; 294 | 295 | case self::ST_NAMESPACE_FOUND: 296 | $state=($tnum==T_WHITESPACE) ? self::ST_NAMESPACE_2 : self::ST_OUT; 297 | break; 298 | 299 | case self::ST_NAMESPACE_2: 300 | switch($tnum) { 301 | case T_STRING: 302 | $name .=$tvalue; 303 | break; 304 | case T_NS_SEPARATOR: 305 | $name .= '\\'; 306 | break; 307 | default: 308 | $ns=$name; 309 | $state=self::ST_OUT; 310 | } 311 | break; 312 | 313 | 314 | case self::ST_FUNCTION_FOUND: 315 | if (($tnum==-1)&&($tvalue=='(')) { 316 | // Closure : Ignore (no function name to get here) 317 | $state=self::ST_OUT; 318 | break; 319 | } 320 | //-- Function returning ref: keep looking for name 321 | if ($tnum==-1 && $tvalue=='&') break; 322 | // No break here ! 323 | case self::ST_CLASS_FOUND: 324 | if ($tnum==T_STRING) { 325 | self::addSymbol($state,self::combineNSSymbol($ns,$tvalue)); 326 | } else { 327 | throw new \Exception('Unrecognized token for class/function definition' 328 | ."(type=$tnum ($tname);value='$tvalue'). String expected"); 329 | } 330 | $state=self::ST_SKIPPING_BLOCK_NOSTRING; 331 | $block_level=0; 332 | break; 333 | 334 | case self::ST_CONST_FOUND: 335 | if ($tnum==T_STRING) { 336 | self::addSymbol(self::T_CONSTANT,self::combineNSSymbol($ns,$tvalue)); 337 | } 338 | else { 339 | throw new \Exception('Unrecognized token for constant definition' 340 | ."(type=$tnum ($tname);value='$tvalue'). String expected"); 341 | } 342 | $state=self::ST_OUT; 343 | break; 344 | 345 | case self::ST_SKIPPING_BLOCK_STRING: 346 | if ($tnum==-1 && $tvalue=='"') 347 | $state=self::ST_SKIPPING_BLOCK_NOSTRING; 348 | break; 349 | 350 | case self::ST_SKIPPING_BLOCK_NOSTRING: 351 | if ($tnum==-1 || $tnum==T_CURLY_OPEN) { 352 | switch($tvalue) { 353 | case '"': 354 | $state=self::ST_SKIPPING_BLOCK_STRING; 355 | break; 356 | case '{': 357 | $block_level++; 358 | //TRACE echo "block_level=$block_level\n"; 359 | break; 360 | case '}': 361 | $block_level--; 362 | if ($block_level==0) $state=self::ST_OUT; 363 | //TRACE echo "block_level=$block_level\n"; 364 | break; 365 | } 366 | } 367 | break; 368 | 369 | case self::ST_DEFINE_FOUND: 370 | if ($tnum==-1 && $tvalue=='(') { 371 | $state=self::ST_DEFINE_2; 372 | } else { 373 | throw new \Exception('Unrecognized token for constant definition' 374 | ."(type=$tnum ($tname);value='$tvalue'). Expected '('"); 375 | } 376 | break; 377 | 378 | case self::ST_DEFINE_2: 379 | // Remember: T_STRING is incorrect in 'define' as constant name. 380 | // Current namespace is ignored in 'define' statement. 381 | if ($tnum==T_CONSTANT_ENCAPSED_STRING) { 382 | $schar=$tvalue[0]; 383 | if ($schar=="'" || $schar=='"') $tvalue=trim($tvalue,$schar); 384 | self::addSymbol(self::T_CONSTANT,$tvalue); 385 | } else { 386 | throw new \Exception('Unrecognized token for constant definition' 387 | ."(type=$tnum ($tname);value='$tvalue'). Expected quoted string constant"); 388 | } 389 | $state=self::ST_SKIPPING_TO_EOL; 390 | break; 391 | 392 | case self::ST_SKIPPING_TO_EOL: 393 | if ($tnum==-1 && $tvalue==';') $state=self::ST_OUT; 394 | break; 395 | } 396 | } 397 | } 398 | 399 | //--- 400 | } // End of class 401 | //=========================================================================== 402 | } // End of namespace 403 | //=========================================================================== 404 | -------------------------------------------------------------------------------- /php/src/internal/tools/Display.php: -------------------------------------------------------------------------------- 1 | | 5 | +----------------------------------------------------------------------+ 6 | | Copyright (c) 2015 The PHP Group | 7 | +----------------------------------------------------------------------+ 8 | | This source file is subject to version 3.01 of the PHP license, | 9 | | that is bundled with this package in the file LICENSE, and is | 10 | | available through the world-wide-web at the following url: | 11 | | http://www.php.net/license/3_01.txt. | 12 | | If you did not receive a copy of the PHP license and are unable to | 13 | | obtain it through the world-wide-web, please send a note to | 14 | | license@php.net so we can mail you a copy immediately. | 15 | +----------------------------------------------------------------------+ 16 | | Author: Francois Laupretre | 17 | +----------------------------------------------------------------------+ 18 | */ 19 | 20 | //============================================================================= 21 | 22 | namespace PCS { 23 | 24 | class Display // Static only 25 | { 26 | //--------- 27 | 28 | private static function displayFormat($format=null) 29 | { 30 | if (is_null($format)||($format==='auto')) { 31 | $format=((php_sapi_name()=='cli') ? 'text' : 'html'); 32 | } 33 | 34 | $format=strtolower($format); 35 | if (($format !== 'text') && ($format !== 'html')) { 36 | throw new \Exception("$format: Unknown display format"); 37 | } 38 | 39 | return $format; 40 | } 41 | 42 | //--------- 43 | 44 | private static function sortByPath($s1,$s2) 45 | { 46 | return strcmp($s1['path'],$s2['path']); 47 | } 48 | 49 | //--------- 50 | 51 | private static function sortByName($s1,$s2) 52 | { 53 | return strcmp($s1['name'],$s2['name']); 54 | } 55 | 56 | //--------- 57 | 58 | public static function showFiles($format=null, $path_to_url_function=null) 59 | { 60 | $format = self::displayFormat($format); 61 | $method = (($format == 'text') ? 'showFilesAsText' : 'showFilesAsHtml'); 62 | self::$method($path_to_url_function); 63 | } 64 | 65 | //--------- 66 | 67 | private static function showFilesAsText($path_to_url_function=null) 68 | { 69 | $infos = Mgr::fileInfos(); 70 | usort($infos, array(__CLASS__,'sortByPath')); 71 | 72 | $size_len=4; 73 | $path_len=12; 74 | foreach($infos as $info) { 75 | $size_len=max($size_len, strlen(strval($info['size']))+2); 76 | $path_len=max($path_len,strlen($info['path'])+2); 77 | } 78 | 79 | echo 80 | str_repeat('-',$size_len+$path_len+7)."\n" 81 | ,'|'.str_pad('Virtual path',$path_len,' ',STR_PAD_BOTH) 82 | ,'|'.str_pad('Size',$size_len,' ',STR_PAD_BOTH) 83 | ,"| L |\n" 84 | ,'|'.str_repeat('-',$path_len) 85 | ,'+'.str_repeat('-',$size_len) 86 | ,"+---|\n"; 87 | 88 | foreach($infos as $info) { 89 | echo 90 | '| '.str_pad($info['path'],$path_len-1,' ',STR_PAD_RIGHT) 91 | ,'| '.str_pad(strval($info['size']),$size_len-1,' ',STR_PAD_RIGHT) 92 | ,'| '.$info['load'] 93 | ," |\n"; 94 | } 95 | } 96 | 97 | //--- 98 | 99 | private static function showFilesAsHtml($path_to_url_function=null) 100 | { 101 | $infos = Mgr::fileInfos(); 102 | usort($infos, array(__CLASS__,'sortByPath')); 103 | 104 | echo ''."\n"; 106 | echo ''."\n"; 107 | foreach($infos as $info) { 108 | echo ''; 115 | echo "\n"; 116 | } 117 | echo "
Virtual pathSizeLoad
'; 109 | if (!is_null($path_to_url_function)) 110 | echo ''; 111 | echo htmlspecialchars($info['path']); 112 | if (!is_null($path_to_url_function)) echo ''; 113 | echo ''.$info['size'].'
' 114 | .$info['load'].'
\n"; 118 | } 119 | 120 | //--------- 121 | 122 | public static function showSymbols($format=null, $path_to_url_function=null) 123 | { 124 | $format = self::displayFormat($format); 125 | $method = (($format == 'text') ? 'showSymbolsAsText' : 'showSymbolsAsHtml'); 126 | self::$method($path_to_url_function); 127 | } 128 | 129 | //--------- 130 | 131 | private static function showSymbolsAsText($path_to_url_function=null) 132 | { 133 | $infos = Mgr::symbolInfos(); 134 | usort($infos, array(__CLASS__,'sortByName')); 135 | 136 | $type_len = 4; 137 | $name_len=4; 138 | $path_len=12; 139 | foreach($infos as $info) { 140 | $type_len=max($type_len, strlen($info['type'])+2); 141 | $name_len=max($name_len, strlen($info['name'])+2); 142 | $path_len=max($path_len,strlen($info['path'])+2); 143 | } 144 | 145 | echo 146 | str_repeat('-',$type_len+$name_len+$path_len+8)."\n" 147 | ,'|'.str_pad('Type',$type_len,' ',STR_PAD_BOTH) 148 | ,'|'.str_pad('Name',$name_len,' ',STR_PAD_BOTH) 149 | ,'|'.str_pad('Virtual path',$path_len,' ',STR_PAD_BOTH) 150 | ,"| L |\n" 151 | ,'|'.str_repeat('-',$type_len) 152 | ,'+'.str_repeat('-',$name_len) 153 | ,'+'.str_repeat('-',$path_len) 154 | ,"+---|\n"; 155 | 156 | foreach($infos as $info) { 157 | echo 158 | '| '.str_pad(ucfirst($info['type']),$type_len-1,' ',STR_PAD_RIGHT) 159 | ,'| '.str_pad($info['name'],$name_len-1,' ',STR_PAD_RIGHT) 160 | ,'| '.str_pad($info['path'],$path_len-1,' ',STR_PAD_RIGHT) 161 | ,'| '.$info['load'] 162 | ," |\n"; 163 | } 164 | } 165 | 166 | //--- 167 | 168 | private static function showSymbolsAsHtml($path_to_url_function=null) 169 | { 170 | $infos = Mgr::symbolInfos(); 171 | usort($infos, array(__CLASS__,'sortByName')); 172 | 173 | echo ''."\n"; 175 | echo ''."\n"; 176 | foreach($infos as $info) { 177 | echo ''; 179 | echo ''; 186 | echo "\n"; 187 | } 188 | echo "
TypeNameVirtual pathLoad
'; 178 | echo '
'.ucfirst($info['type']).'
'.$info['name'].''; 180 | if (!is_null($path_to_url_function)) 181 | echo ''; 182 | echo htmlspecialchars($info['path']); 183 | if (!is_null($path_to_url_function)) echo ''; 184 | echo '
' 185 | .$info['load'].'
\n"; 189 | } 190 | 191 | //--- 192 | } // End of class 193 | //=========================================================================== 194 | } // End of namespace 195 | //=========================================================================== 196 | ?> 197 | -------------------------------------------------------------------------------- /php/src/internal/tools/embed.php: -------------------------------------------------------------------------------- 1 | | 5 | +----------------------------------------------------------------------+ 6 | | Copyright (c) 2015 The PHP Group | 7 | +----------------------------------------------------------------------+ 8 | | This source file is subject to version 3.01 of the PHP license, | 9 | | that is bundled with this package in the file LICENSE, and is | 10 | | available through the world-wide-web at the following url: | 11 | | http://www.php.net/license/3_01.txt. | 12 | | If you did not receive a copy of the PHP license and are unable to | 13 | | obtain it through the world-wide-web, please send a note to | 14 | | license@php.net so we can mail you a copy immediately. | 15 | +----------------------------------------------------------------------+ 16 | | Author: Francois Laupretre | 17 | +----------------------------------------------------------------------+ 18 | */ 19 | // :ignore-file 20 | 21 | //============================================================================= 22 | 23 | namespace PCS\Parser { 24 | 25 | class File 26 | { 27 | const DESCRIPTOR_VERSION = 0; 28 | 29 | private $data; /* File contents */ 30 | private $path; 31 | private $vpath; 32 | 33 | /*------------------------------------------------------------------*/ 34 | 35 | public function __construct($path, $vpath) 36 | { 37 | $this->path = $path; 38 | $this->vpath = $vpath; 39 | 40 | $this->data = file_get_contents($path); 41 | if ($this->data === FALSE) { 42 | throw new Exception($path.": Cannot read file"); 43 | } 44 | } 45 | 46 | /*------------------------------------------------------------------*/ 47 | 48 | public static function sortByVpath($f1,$f2) 49 | { 50 | return strcmp($f1->vpath, $f2->vpath); 51 | } 52 | 53 | /*------------------------------------------------------------------*/ 54 | 55 | private function is_php_source() 56 | { 57 | return ((strlen($this->data) >= 5) && (substr($this->data, 0, 5)=='is_php_source()) return; 78 | 79 | $res = ''; 80 | 81 | foreach (token_get_all($this->data) as $token) { 82 | if (is_string($token)) { 83 | $res .= $token; 84 | } else { 85 | switch($token[0]) { 86 | case T_DOC_COMMENT: 87 | $res .= self::strip_string($token[1]); 88 | break; 89 | case T_COMMENT: 90 | // Keep parser directives only 91 | $keep = false; 92 | if (strlen($token[1]) > 3) { 93 | $s = ltrim(substr($token[1], 2)); 94 | if ((strlen($s) > 9) && (substr($s, 0, 9) == ':')) { 95 | $keep = true; 96 | } 97 | } 98 | if ($keep) { 99 | $res .= $token[1]; 100 | } else { 101 | $res .= self::strip_string($token[1]); 102 | } 103 | break; 104 | case T_WHITESPACE: 105 | // reduce wide spaces 106 | $whitespace = preg_replace('{[ \t]+}', ' ', $token[1]); 107 | // normalize newlines to \n 108 | $whitespace = preg_replace('{(?:\r\n|\r|\n)}', "\n", $whitespace); 109 | // trim leading spaces 110 | $whitespace = preg_replace('{\n +}', "\n", $whitespace); 111 | $res .= $whitespace; 112 | break; 113 | default: 114 | $res .= $token[1]; 115 | } 116 | } 117 | } 118 | 119 | $this->data = $res; 120 | } 121 | 122 | /*------------------------------------------------------------------*/ 123 | /* Returns the definition of the string containing the data */ 124 | 125 | function dump_data($prefix, $index) 126 | { 127 | $ret="static char ".$prefix.'_string'.$index."[]= { /* ".$this->vpath." */\n "; 128 | $len = strlen($this->data); 129 | if ($len) { 130 | for ($i = 0; $i < $len; $i++) { 131 | $ret .= ord($this->data[$i]).', '; 132 | if ($i % 16 == 15) { 133 | $ret .= "\n "; 134 | } 135 | } 136 | } 137 | $ret .= "0 };\n\n"; 138 | 139 | return $ret; 140 | } 141 | 142 | /*------------------------------------------------------------------*/ 143 | /* Return the descriptor struct definition */ 144 | 145 | function dump_descriptor($prefix, $index) 146 | { 147 | return " { ".self::DESCRIPTOR_VERSION.", ".$prefix.'_string'.$index 148 | .", ".strlen($this->data).", \"".$this->vpath."\", " 149 | .strlen($this->vpath)." },\n"; 150 | } 151 | 152 | /*------------------------------------------------------------------*/ 153 | } // End of class 154 | //============================================================================= 155 | 156 | function dump_files($prefix, $table) 157 | { 158 | usort($table, array("PCS\\Parser\\File", 'sortByVpath')); 159 | 160 | $ret = ''; 161 | foreach($table as $index => $file) { 162 | $file->strip(); 163 | $ret .= $file->dump_data($prefix, $index); 164 | } 165 | 166 | $ret .= "\nstatic PCS_DESCRIPTOR ".$prefix."[".(count($table) + 1)."] = {\n"; 167 | foreach($table as $index => $file) { 168 | $ret .= $file->dump_descriptor($prefix, $index); 169 | } 170 | $ret .= " { ".File::DESCRIPTOR_VERSION.", NULL }\n};\n"; 171 | 172 | return $ret; 173 | } 174 | 175 | /*------------------------------------------------------------------*/ 176 | 177 | function register_path($path, $vpath, &$table) 178 | { 179 | $type = filetype($path); 180 | if ($type === false) { 181 | throw new Exception($path.": Cannot get file type"); 182 | } 183 | 184 | switch($type) { 185 | case 'dir': 186 | foreach(scandir($path) as $entry) { 187 | if (($entry === '.') || ($entry === '..')) { 188 | continue; 189 | } 190 | $epath = $path.DIRECTORY_SEPARATOR.$entry; 191 | $evpath = (($vpath==='') ? $entry : ($vpath.'/'.$entry)); 192 | register_path($epath, $evpath, $table); 193 | } 194 | break; 195 | 196 | case 'file': 197 | $table[] = new File($path, $vpath); 198 | break; 199 | 200 | default: 201 | echo $path.": Unsupported file type ($type) - ignoring\n"; 202 | } 203 | } 204 | 205 | /*------------------------------------------------------------------*/ 206 | // MAIN 207 | 208 | $prog = basename($argv[0]); 209 | 210 | if ($argc < 4) { 211 | throw new Exception("Usage: ".$argv[0]." \n"); 212 | } 213 | 214 | if ($argv[1] == '-s') { /* Ignore obsolete option */ 215 | array_shift($argv); 216 | } 217 | 218 | $ipath = $argv[1]; 219 | $prefix = $argv[2]; 220 | $opath = $argv[3]; 221 | 222 | $table = array(); 223 | 224 | register_path($ipath, '', $table); 225 | 226 | $output = 227 | "/* This file was generated by the PCS embed utility */ 228 | /*-------------------- DO NOT MODIFY --------------------*/\n\n" 229 | . dump_files($prefix, $table); 230 | 231 | file_put_contents($opath, $output); 232 | 233 | //============================================================================= 234 | } 235 | ?> 236 | -------------------------------------------------------------------------------- /php_pcs.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PCS extension | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2015 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt. | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Author: Francois Laupretre | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | /* Uncomment to display debug messages */ 20 | /*#define PCS_DEBUG*/ 21 | /* Uncomment to prefix debug messages with timestamps */ 22 | /*#define UT_DBG_TIMESTAMPS*/ 23 | 24 | /*============================================================================*/ 25 | 26 | #ifdef PCS_DEBUG 27 | #define UT_DEBUG 28 | #endif 29 | 30 | #ifdef HAVE_CONFIG_H 31 | #include "config.h" 32 | #endif 33 | 34 | #include "php.h" 35 | #include "zend_extensions.h" 36 | #include "ext/standard/info.h" 37 | 38 | #include "pecl-compat/compat.h" 39 | #include "pecl-utils/utils.h" 40 | 41 | /*---------------------------------------------------------------*/ 42 | 43 | #define MODULE_NAME PHP_PCS_EXTNAME 44 | #define MODULE_VERSION PHP_PCS_VERSION 45 | 46 | /*---------------------------------------------------------------*/ 47 | 48 | #include "php_pcs.h" 49 | #include "./client.h" 50 | 51 | #include "src/PCS_Utils.h" 52 | #include "src/PCS_Tree.h" 53 | #include "src/PCS_Class.h" 54 | #include "src/PCS_Stream.h" 55 | #include "src/PCS_Loader.h" 56 | #include "src/PCS_API.h" 57 | #include "src/PCS_Info.h" 58 | 59 | /*------------------------*/ 60 | /* Include embedded PHP code */ 61 | 62 | #include "php/phpc/tools_code.phpc" 63 | 64 | /*------------------------*/ 65 | 66 | #ifdef COMPILE_DL_PCS 67 | ZEND_TSRMLS_CACHE_DEFINE(); 68 | ZEND_GET_MODULE(pcs) 69 | #endif 70 | 71 | /*------------------------*/ 72 | 73 | ZEND_BEGIN_MODULE_GLOBALS(pcs) 74 | 75 | zend_function *autoload_func; /* Original content of EG(autoload_func) */ 76 | 77 | ZEND_END_MODULE_GLOBALS(pcs) 78 | 79 | ZEND_DECLARE_MODULE_GLOBALS(pcs) 80 | 81 | #define PCS_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(pcs, v) 82 | 83 | /*------------------------*/ 84 | /* Including C code allows to export only the symbols we want to make public */ 85 | 86 | #include "pecl-utils/utils.c" 87 | 88 | #include "src/PCS_Utils.c" 89 | #include "src/PCS_Tree.c" 90 | #include "src/PCS_Class.c" 91 | #include "src/PCS_Stream.c" 92 | #include "src/PCS_Loader.c" 93 | #include "src/PCS_API.c" 94 | #include "src/PCS_Info.c" 95 | 96 | /*---------------------------------------------------------------*/ 97 | /* phpinfo() output */ 98 | 99 | static PHP_MINFO_FUNCTION(pcs) 100 | { 101 | char buf[10]; 102 | zend_ulong modes[3]; 103 | PCS_Node *node; 104 | 105 | php_info_print_table_start(); 106 | 107 | php_info_print_table_row(2, "PHP Code Service", "enabled"); 108 | php_info_print_table_row(2, "Version", PHP_PCS_VERSION); 109 | 110 | sprintf(buf, "%d", (int)zend_hash_num_elements(fileList)); 111 | php_info_print_table_row(2, "File count",buf); 112 | php_info_print_table_end(); 113 | 114 | modes[0] = modes[1] = modes[2] = 0; 115 | ZEND_HASH_FOREACH_PTR(fileList, node) { 116 | modes [node->load_mode -1 ]++; 117 | } ZEND_HASH_FOREACH_END(); 118 | 119 | php_info_print_table_start(); 120 | 121 | php_info_print_table_colspan_header(2, "Load mode"); 122 | 123 | sprintf(buf, "%lu", modes[PCS_LOAD_AUTOLOAD -1]); 124 | php_info_print_table_row(2, "Autoloaded",buf); 125 | 126 | sprintf(buf, "%lu", modes[PCS_LOAD_RINIT -1]); 127 | php_info_print_table_row(2, "Loaded at RINIT",buf); 128 | 129 | sprintf(buf, "%lu", modes[PCS_LOAD_NONE -1]); 130 | php_info_print_table_row(2, "Not loaded",buf); 131 | 132 | php_info_print_table_end(); 133 | } 134 | 135 | /*---------------------------------------------------------------*/ 136 | /* Initialize a new zend_pcs_globals struct during thread spin-up */ 137 | 138 | static void pcs_globals_ctor(zend_pcs_globals * globals TSRMLS_DC) 139 | { 140 | #ifdef COMPILE_DL_PCS 141 | ZEND_TSRMLS_CACHE_UPDATE(); 142 | #endif 143 | 144 | CLEAR_DATA(*globals); /* Init everything to 0/NULL */ 145 | } 146 | 147 | /*------------------------*/ 148 | /* Resources allocated during initialization are freed here */ 149 | 150 | static void pcs_globals_dtor(zend_pcs_globals * globals TSRMLS_DC) 151 | { 152 | } 153 | 154 | /*---------------------------------------------------------------*/ 155 | 156 | static PHP_RINIT_FUNCTION(pcs) 157 | { 158 | DBG_MSG("-> PCS RINIT"); 159 | 160 | in_startup = 0; 161 | 162 | if (RINIT_PCS_Utils(TSRMLS_C) == FAILURE) return FAILURE; 163 | if (RINIT_PCS_Tree(TSRMLS_C) == FAILURE) return FAILURE; 164 | if (RINIT_PCS_Class(TSRMLS_C) == FAILURE) return FAILURE; 165 | if (RINIT_PCS_Stream(TSRMLS_C) == FAILURE) return FAILURE; 166 | if (RINIT_PCS_Loader(TSRMLS_C) == FAILURE) return FAILURE; 167 | if (RINIT_PCS_API(TSRMLS_C) == FAILURE) return FAILURE; 168 | if (RINIT_PCS_Info(TSRMLS_C) == FAILURE) return FAILURE; 169 | 170 | DBG_MSG("<- PCS RINIT"); 171 | return SUCCESS; 172 | } 173 | 174 | /*---------------------------------------------------------------*/ 175 | 176 | static PHP_RSHUTDOWN_FUNCTION(pcs) 177 | { 178 | if (RSHUTDOWN_PCS_Info(TSRMLS_C) == FAILURE) return FAILURE; 179 | if (RSHUTDOWN_PCS_API(TSRMLS_C) == FAILURE) return FAILURE; 180 | if (RSHUTDOWN_PCS_Loader(TSRMLS_C) == FAILURE) return FAILURE; 181 | if (RSHUTDOWN_PCS_Stream(TSRMLS_C) == FAILURE) return FAILURE; 182 | if (RSHUTDOWN_PCS_Class(TSRMLS_C) == FAILURE) return FAILURE; 183 | if (RSHUTDOWN_PCS_Tree(TSRMLS_C) == FAILURE) return FAILURE; 184 | if (RSHUTDOWN_PCS_Utils(TSRMLS_C) == FAILURE) return FAILURE; 185 | 186 | return SUCCESS; 187 | } 188 | 189 | /*---------------------------------------------------------------*/ 190 | 191 | static PHP_MINIT_FUNCTION(pcs) 192 | { 193 | #ifndef PHP_7 194 | /* In some PHP versions, valgrind reports a conditional jump on 195 | uninitialized data when calling php_error() during MINIT because 196 | EG(exception is not initialized yet. */ 197 | 198 | EG(exception) = NULL; 199 | #endif 200 | 201 | DBG_INIT(); 202 | DBG_MSG("-> PCS MINIT"); 203 | 204 | ZEND_INIT_MODULE_GLOBALS(pcs, pcs_globals_ctor, NULL); 205 | 206 | 207 | if (MINIT_PCS_Utils(TSRMLS_C) == FAILURE) return FAILURE; 208 | if (MINIT_PCS_Tree(TSRMLS_C) == FAILURE) return FAILURE; 209 | if (MINIT_PCS_Class(TSRMLS_C) == FAILURE) return FAILURE; 210 | if (MINIT_PCS_Stream(TSRMLS_C) == FAILURE) return FAILURE; 211 | if (MINIT_PCS_Loader(TSRMLS_C) == FAILURE) return FAILURE; 212 | if (MINIT_PCS_API(TSRMLS_C) == FAILURE) return FAILURE; 213 | if (MINIT_PCS_Info(TSRMLS_C) == FAILURE) return FAILURE; 214 | 215 | /* Register embedded PHP code (tools) */ 216 | 217 | if (PCS_registerEmbedded(tools_code, IMM_STRL("internal/tools"), 0) == FAILURE) { 218 | return FAILURE; 219 | } 220 | 221 | DBG_MSG("<- PCS MINIT"); 222 | return SUCCESS; 223 | } 224 | 225 | /*---------------------------------------------------------------*/ 226 | 227 | static PHP_MSHUTDOWN_FUNCTION(pcs) 228 | { 229 | pcs_globals_dtor(ZEND_MODULE_GLOBALS_BULK(pcs) TSRMLS_CC); 230 | 231 | if (MSHUTDOWN_PCS_Info(TSRMLS_C) == FAILURE) return FAILURE; 232 | if (MSHUTDOWN_PCS_API(TSRMLS_C) == FAILURE) return FAILURE; 233 | if (MSHUTDOWN_PCS_Loader(TSRMLS_C) == FAILURE) return FAILURE; 234 | if (MSHUTDOWN_PCS_Stream(TSRMLS_C) == FAILURE) return FAILURE; 235 | if (MSHUTDOWN_PCS_Class(TSRMLS_C) == FAILURE) return FAILURE; 236 | if (MSHUTDOWN_PCS_Tree(TSRMLS_C) == FAILURE) return FAILURE; 237 | if (MSHUTDOWN_PCS_Utils(TSRMLS_C) == FAILURE) return FAILURE; 238 | 239 | return SUCCESS; 240 | } 241 | 242 | /*---------------------------------------------------------------*/ 243 | /*-- Module definition --*/ 244 | 245 | ZEND_BEGIN_ARG_INFO_EX(_pcs_autoload_arginfo, 0, 0, 1) 246 | ZEND_ARG_INFO(0, symbol) 247 | ZEND_ARG_INFO(0, type) 248 | ZEND_END_ARG_INFO() 249 | 250 | ZEND_BEGIN_ARG_INFO_EX(_pcs_autoload_register_arginfo, 0, 0, 0) 251 | ZEND_ARG_INFO(0, autoload_function) 252 | ZEND_ARG_INFO(0, throw) 253 | ZEND_ARG_INFO(0, prepend) 254 | ZEND_END_ARG_INFO() 255 | 256 | static zend_function_entry pcs_functions[] = { 257 | PHP_FE(_pcs_autoload, _pcs_autoload_arginfo) 258 | PHP_FE(_pcs_autoload_register, _pcs_autoload_register_arginfo) 259 | PHP_FE_END 260 | }; 261 | 262 | static const zend_module_dep pcs_deps[] = { 263 | ZEND_MOD_REQUIRED("tokenizer") 264 | ZEND_MOD_REQUIRED("pcre") 265 | ZEND_MOD_REQUIRED("SPL") 266 | ZEND_MOD_END 267 | }; 268 | 269 | zend_module_entry pcs_module_entry = { 270 | STANDARD_MODULE_HEADER_EX, 271 | NULL, 272 | pcs_deps, 273 | MODULE_NAME, 274 | pcs_functions, 275 | PHP_MINIT(pcs), 276 | PHP_MSHUTDOWN(pcs), 277 | PHP_RINIT(pcs), 278 | PHP_RSHUTDOWN(pcs), 279 | PHP_MINFO(pcs), 280 | MODULE_VERSION, 281 | STANDARD_MODULE_PROPERTIES 282 | }; 283 | 284 | /*---------------------------------------------------------------*/ 285 | -------------------------------------------------------------------------------- /php_pcs.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PCS extension | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2015 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt. | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Author: Francois Laupretre | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifndef __PHP_PCS_H 20 | #define __PHP_PCS_H 21 | 22 | /*============================================================================*/ 23 | 24 | #define PHP_PCS_VERSION "1.3.7" /* The extension version */ 25 | 26 | #define PHP_PCS_EXTNAME "pcs" 27 | 28 | extern zend_module_entry pcs_module_entry; 29 | 30 | #define phpext_pcs_ptr &pcs_module_entry 31 | 32 | /*============================================================================*/ 33 | #endif /* __PHP_PCS_H */ 34 | -------------------------------------------------------------------------------- /src/PCS_API.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PCS extension | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2005-2015 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt. | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Author: Francois Laupretre | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #ifdef PHP_WIN32 24 | # include "config.w32.h" 25 | #else 26 | # include 27 | #endif 28 | 29 | #if HAVE_UNISTD_H 30 | # include 31 | #endif 32 | 33 | #if HAVE_SCANDIR && HAVE_ALPHASORT && HAVE_DIRENT_H 34 | # include 35 | #endif 36 | 37 | #include "ext/standard/file.h" 38 | #include "ext/standard/php_filestat.h" 39 | #include "main/php_scandir.h" 40 | #include "main/spprintf.h" 41 | #include "main/php.h" 42 | #include "zend_list.h" 43 | 44 | /*===============================================================*/ 45 | /* Public API */ 46 | 47 | /*--------------------*/ 48 | 49 | ZEND_DLEXPORT long PCS_registerEmbedded(PCS_DESCRIPTOR *list 50 | , const char *virtual_path, size_t virtual_path_len, zend_ulong flags) 51 | { 52 | PCS_Node *node; 53 | long count; 54 | char *path; 55 | size_t path_len; 56 | 57 | if (! in_startup) { 58 | php_error(E_CORE_ERROR, "PCS_registerEmbedded() can be called during MINIT only"); 59 | return FAILURE; 60 | } 61 | 62 | if (PCS_Utils_assertModuleIsStarted() == FAILURE) { 63 | return FAILURE; 64 | } 65 | 66 | count = 0; 67 | while (list->data) { 68 | /* Only descriptor version 0 can be handled */ 69 | if (list->version != 0) { 70 | php_error(E_CORE_ERROR,"Cannot handle descriptor version (%d)", list->version); 71 | return FAILURE; 72 | } 73 | 74 | if (virtual_path_len) { 75 | spprintf(&path, 0, "%s/%s", virtual_path, list->path); 76 | path_len = virtual_path_len + list->path_len + 1; 77 | } else { 78 | spprintf(&path, 0, "%s", list->path); 79 | path_len = list->path_len; 80 | } 81 | 82 | node = PCS_Tree_addFile(path, path_len, list->data 83 | , list->data_len, 0, flags); 84 | EFREE(path); 85 | if (! node) return FAILURE; 86 | list++; 87 | count++; 88 | } 89 | 90 | return count; 91 | } 92 | 93 | /*--------------------*/ 94 | 95 | ZEND_DLEXPORT PCS_ID PCS_registerData(char *data, size_t data_len 96 | , const char *path, size_t path_len, zend_ulong flags) 97 | { 98 | PCS_Node *node; 99 | 100 | if (! in_startup) { 101 | php_error(E_CORE_ERROR, "PCS_registerData() can be called during MINIT only"); 102 | return FAILURE; 103 | } 104 | 105 | if (PCS_Utils_assertModuleIsStarted() == FAILURE) { 106 | return FAILURE; 107 | } 108 | 109 | node = PCS_Tree_addFile(path, path_len, data, data_len, 0, flags); 110 | return (node ? PCS_FILE_ID(node) : FAILURE); 111 | } 112 | 113 | /*--------------------*/ 114 | /* Note: Stream wrapper open/opendir functions cannot be used during MINIT */ 115 | /* So, we need to revert to stdio functions. */ 116 | 117 | #define CLEANUP_PCS_registerPath() { \ 118 | if (fp) fclose(fp); \ 119 | PFREE(data); \ 120 | } 121 | 122 | #define ABORT_PCS_registerPath() { \ 123 | CLEANUP_PCS_registerPath(); \ 124 | return FAILURE; \ 125 | } 126 | 127 | ZEND_DLEXPORT long PCS_registerPath(const char *filename, size_t filename_len 128 | , const char *virtual_path, size_t virtual_path_len, zend_ulong flags) 129 | { 130 | char *data = NULL, *sub_fname, *sub_vpath, *dname; 131 | size_t datalen, sub_fname_len, sub_vpath_len; 132 | long status, fcount = 0; 133 | FILE *fp = NULL; 134 | struct stat st; 135 | struct dirent **namelist; 136 | int nb, i; 137 | 138 | if (! in_startup) { 139 | php_error(E_CORE_ERROR, "PCS_registerPath() can be called during MINIT only"); 140 | ABORT_PCS_registerPath(); 141 | } 142 | 143 | if (PCS_Utils_assertModuleIsStarted() == FAILURE) { 144 | ABORT_PCS_registerPath(); 145 | } 146 | 147 | 148 | if (stat(filename, &st)) { 149 | php_error(E_CORE_ERROR, "%s: %s (errno=%d)", filename, strerror(errno), errno); 150 | ABORT_PCS_registerPath(); 151 | } 152 | 153 | /* If path is a directory */ 154 | 155 | if (S_ISDIR(st.st_mode)) { 156 | if (! PCS_Tree_addDir(virtual_path, virtual_path_len, flags)) { 157 | ABORT_PCS_registerPath(); 158 | } 159 | 160 | /* Recurse on dir entries */ 161 | 162 | nb = php_scandir(filename, &namelist, 0, NULL); 163 | if (nb < 0) { 164 | php_error(E_CORE_ERROR,"%s: Cannot scan directory", filename); 165 | return FAILURE; 166 | } 167 | if (nb > 0) { 168 | for (i = 0; i < nb ; i++) { 169 | dname = namelist[i]->d_name; 170 | if ((dname[0] == '.') && ((dname[1] == '\0') || ((dname[1] == '.') || (dname[2] == '\0')))) { 171 | continue; 172 | } 173 | spprintf(&sub_fname, 0, "%s%c%s", filename, PHP_DIR_SEPARATOR, dname); 174 | sub_fname_len = strlen(sub_fname); 175 | spprintf(&sub_vpath, 0, "%s/%s", virtual_path, dname); 176 | sub_vpath_len = strlen(sub_vpath); 177 | status = PCS_registerPath(sub_fname, sub_fname_len, sub_vpath, sub_vpath_len, flags); 178 | EFREE(sub_fname); 179 | EFREE(sub_vpath); 180 | if (status == FAILURE) { 181 | /* Fatal error: don't care about namelist mem leak */ 182 | ABORT_PCS_registerPath(); 183 | } 184 | fcount += status; 185 | free(namelist[i]); 186 | } 187 | free(namelist); 188 | } 189 | 190 | /* If path is a regular file */ 191 | 192 | } else if (S_ISREG(st.st_mode)) { 193 | 194 | fp=fopen(filename, "rb"); 195 | if (!fp) { 196 | php_error(E_CORE_ERROR, "%s: %s (errno=%d)", filename, strerror(errno), errno); 197 | ABORT_PCS_registerPath(); 198 | } 199 | fstat(fileno(fp),&st); 200 | datalen = (size_t)(st.st_size); 201 | PALLOCATE(data, datalen + 1); 202 | if (datalen) { 203 | while (!fread(data, datalen, 1, fp)) {} 204 | } 205 | data[datalen]='\0'; 206 | if (! PCS_Tree_addFile(virtual_path, virtual_path_len, data, datalen, 1, flags)) { 207 | ABORT_PCS_registerPath(); 208 | } 209 | data = NULL; 210 | fcount = 1; 211 | 212 | /* Other file types are silently ignored */ 213 | } 214 | 215 | CLEANUP_PCS_registerPath(); 216 | return fcount; 217 | } 218 | 219 | /*--------------------*/ 220 | 221 | ZEND_DLEXPORT int PCS_loadScript(PCS_ID id, int throw TSRMLS_DC) 222 | { 223 | PCS_Node *node; 224 | 225 | if (in_startup) { 226 | if (throw) { 227 | THROW_EXCEPTION("PCS_loadScript() cannot be called during MINIT"); 228 | } 229 | return FAILURE; 230 | } 231 | 232 | if (PCS_Utils_assertModuleIsStarted() == FAILURE) { 233 | if (throw) { 234 | THROW_EXCEPTION("PCS module is not active"); 235 | } 236 | return FAILURE; 237 | } 238 | 239 | node = PCS_Tree_getNodeFromID(id); 240 | if (! node) { 241 | if (throw) { 242 | THROW_EXCEPTION_1("Cannot get PCS node from ID (%ld)", id); 243 | } 244 | return FAILURE; 245 | } 246 | 247 | return PCS_Loader_loadNode(node, throw TSRMLS_CC); 248 | } 249 | 250 | /*--------------------*/ 251 | 252 | ZEND_DLEXPORT char *PCS_getPath(PCS_ID id) 253 | { 254 | PCS_Node *node; 255 | 256 | if (PCS_Utils_assertModuleIsStarted() == FAILURE) { 257 | return NULL; 258 | } 259 | 260 | node = PCS_Tree_getNodeFromID(id); 261 | if (! node) { 262 | return NULL; 263 | } 264 | 265 | return ZSTR_VAL(node->path); 266 | } 267 | 268 | /*--------------------*/ 269 | 270 | ZEND_DLEXPORT PCS_ID PCS_getID(const char *path, size_t path_len) 271 | { 272 | PCS_Node *node; 273 | 274 | if (PCS_Utils_assertModuleIsStarted() == FAILURE) { 275 | return FAILURE; 276 | } 277 | 278 | node = PCS_Tree_getNodeFromPath(path, path_len); 279 | if (! node) { 280 | return FAILURE; 281 | } 282 | 283 | return PCS_FILE_ID(node); 284 | } 285 | 286 | /*===============================================================*/ 287 | 288 | static zend_always_inline int MINIT_PCS_API(TSRMLS_D) 289 | { 290 | return SUCCESS; 291 | } 292 | 293 | /*---------------------------------------------------------------*/ 294 | 295 | static zend_always_inline int MSHUTDOWN_PCS_API(TSRMLS_D) 296 | { 297 | return SUCCESS; 298 | } 299 | 300 | /*---------------------------------------------------------------*/ 301 | 302 | static zend_always_inline int RINIT_PCS_API(TSRMLS_D) 303 | { 304 | return SUCCESS; 305 | } 306 | /*---------------------------------------------------------------*/ 307 | 308 | static zend_always_inline int RSHUTDOWN_PCS_API(TSRMLS_D) 309 | { 310 | return SUCCESS; 311 | } 312 | 313 | /*===============================================================*/ 314 | -------------------------------------------------------------------------------- /src/PCS_API.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PCS extension | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2015 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt. | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Author: Francois Laupretre | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifndef __PCS_API_H 20 | #define __PCS_API_H 21 | 22 | /*============================================================================*/ 23 | 24 | /*============================================================================*/ 25 | #endif 26 | -------------------------------------------------------------------------------- /src/PCS_Class.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PCS extension | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2005-2015 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt. | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Author: Francois Laupretre | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | /*---------------------------------------------------------------*/ 20 | /* {{{ proto string \PCS\Mgr::__construct() */ 21 | /* This private method is never called. It exists only to prevent instanciation 22 | * from user code using a 'new' directive */ 23 | 24 | static PHP_METHOD(PCS, __construct) 25 | {} 26 | 27 | /*---------------------------------------------------------------*/ 28 | 29 | static zend_function_entry PCS_methods[] = { 30 | PHP_ME(PCS, __construct, UT_noarg_arginfo, ZEND_ACC_PRIVATE) 31 | PHP_ME(PCS, getFunction, UT_1arg_arginfo, 32 | ZEND_ACC_STATIC | ZEND_ACC_PUBLIC) 33 | PHP_ME(PCS, getConstant, UT_1arg_arginfo, 34 | ZEND_ACC_STATIC | ZEND_ACC_PUBLIC) 35 | PHP_ME(PCS, getClass, UT_1arg_arginfo, 36 | ZEND_ACC_STATIC | ZEND_ACC_PUBLIC) 37 | PHP_ME(PCS, requireFunction, UT_1arg_arginfo, 38 | ZEND_ACC_STATIC | ZEND_ACC_PUBLIC) 39 | PHP_ME(PCS, requireConstant, UT_1arg_arginfo, 40 | ZEND_ACC_STATIC | ZEND_ACC_PUBLIC) 41 | PHP_ME(PCS, requireClass, UT_1arg_arginfo, 42 | ZEND_ACC_STATIC | ZEND_ACC_PUBLIC) 43 | PHP_ME(PCS, fileCount, UT_noarg_arginfo, 44 | ZEND_ACC_STATIC | ZEND_ACC_PUBLIC) 45 | PHP_ME(PCS, fileInfos, UT_noarg_arginfo, 46 | ZEND_ACC_STATIC | ZEND_ACC_PUBLIC) 47 | PHP_ME(PCS, symbolInfos, UT_noarg_arginfo, 48 | ZEND_ACC_STATIC | ZEND_ACC_PUBLIC) 49 | {NULL, NULL, NULL, 0, 0} 50 | }; 51 | 52 | /*===============================================================*/ 53 | 54 | static zend_always_inline int MINIT_PCS_Class(TSRMLS_D) 55 | { 56 | zend_class_entry ce; 57 | 58 | INIT_CLASS_ENTRY(ce, "PCS\\Mgr", PCS_methods); 59 | zend_register_internal_class(&ce TSRMLS_CC); 60 | 61 | return SUCCESS; 62 | } 63 | 64 | /*---------------------------------------------------------------*/ 65 | 66 | static zend_always_inline int MSHUTDOWN_PCS_Class(TSRMLS_D) 67 | { 68 | return SUCCESS; 69 | } 70 | 71 | /*---------------------------------------------------------------*/ 72 | 73 | static zend_always_inline int RINIT_PCS_Class(TSRMLS_D) 74 | { 75 | return SUCCESS; 76 | } 77 | /*---------------------------------------------------------------*/ 78 | 79 | static zend_always_inline int RSHUTDOWN_PCS_Class(TSRMLS_D) 80 | { 81 | return SUCCESS; 82 | } 83 | 84 | /*===============================================================*/ 85 | -------------------------------------------------------------------------------- /src/PCS_Class.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PCS extension | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2015 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt. | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Author: Francois Laupretre | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifndef __PCS_CLASS_H 20 | #define __PCS_CLASS_H 21 | 22 | /*============================================================================*/ 23 | 24 | static PHP_METHOD(PCS, __construct); 25 | 26 | /*============================================================================*/ 27 | #endif 28 | -------------------------------------------------------------------------------- /src/PCS_Info.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PCS extension | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2005-2015 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt. | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Author: Francois Laupretre | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | /*---------------------------------------------------------------*/ 20 | 21 | static PHP_METHOD(PCS, fileCount) 22 | { 23 | RETURN_LONG(zend_hash_num_elements(fileList)); 24 | } 25 | 26 | /*---------------------------------------------------------------*/ 27 | /* Return array of file info 28 | Each file info is an array(flags/load/size/path) */ 29 | 30 | static PHP_METHOD(PCS, fileInfos) 31 | { 32 | PCS_Node *node; 33 | char mode[2]; 34 | 35 | array_init_size(return_value, zend_hash_num_elements(fileList)); 36 | 37 | mode[1] = '\0'; 38 | ZEND_HASH_FOREACH_PTR(fileList, node) { 39 | mode[0] = PCS_Tree_LoadModeToDisplay(node); 40 | 41 | { 42 | #ifdef PHP_7 43 | zval zv, elt; 44 | HashTable *ht; 45 | 46 | array_init_size(&elt, 4); 47 | ht = Z_ARRVAL(elt); 48 | 49 | ZVAL_LONG(&zv, (long)(node->flags)); 50 | zend_hash_str_update(ht, "flags", 5, &zv); 51 | 52 | ZVAL_STRINGL(&zv, mode, 1); 53 | zend_hash_str_update(ht, "load", 4, &zv); 54 | 55 | ZVAL_LONG(&zv, (long)(PCS_FILE_LEN(node))); 56 | zend_hash_str_update(ht, "size", 4, &zv); 57 | 58 | zend_string_addref(node->path); 59 | ZVAL_STR(&zv, node->path); 60 | zend_hash_str_update(ht, "path", 4, &zv); 61 | 62 | zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &elt); 63 | #else 64 | zval *elt; 65 | 66 | MAKE_STD_ZVAL(elt); 67 | array_init_size(elt, 4); 68 | 69 | add_assoc_long(elt, "flags", (long)(node->flags)); 70 | add_assoc_stringl(elt, "load", mode, 1, 1); 71 | add_assoc_long(elt, "size", (long)(PCS_FILE_LEN(node))); 72 | add_assoc_stringl(elt, "path", ZSTR_VAL(node->path), ZSTR_LEN(node->path), 1); 73 | 74 | add_next_index_zval(return_value, elt); 75 | #endif 76 | } 77 | } ZEND_HASH_FOREACH_END(); 78 | } 79 | 80 | /*---------------------------------------------------------------*/ 81 | /* Return array of symbol info 82 | Each symbol info is an array(type/name/path/load) */ 83 | 84 | static PHP_METHOD(PCS, symbolInfos) 85 | { 86 | PCS_Node *node; 87 | char mode[2]; 88 | 89 | array_init_size(return_value, zend_hash_num_elements(symbols)); 90 | 91 | mode[1] = '\0'; 92 | { 93 | #ifdef PHP_7 94 | zval zv, elt; 95 | HashTable *ht; 96 | zend_string *key, *zs; 97 | char *type; 98 | 99 | ZEND_HASH_FOREACH_STR_KEY_PTR(symbols, key, node) { 100 | mode[0] = PCS_Tree_LoadModeToDisplay(node); 101 | 102 | array_init_size(&elt, 4); 103 | ht = Z_ARRVAL(elt); 104 | 105 | type = PCS_Loader_keyTypeString(ZSTR_VAL(key)[0]); 106 | zs = zend_string_init(type, strlen(type), 0); 107 | ZVAL_STR(&zv, zs); 108 | zend_hash_str_update(ht, "type", 4, &zv); 109 | 110 | zs = zend_string_init(ZSTR_VAL(key) + 1, ZSTR_LEN(key) - 1, 0); 111 | ZVAL_STR(&zv, zs); 112 | zend_hash_str_update(ht, "name", 4, &zv); 113 | 114 | ZVAL_STRINGL(&zv, mode, 1); 115 | zend_hash_str_update(ht, "load", 4, &zv); 116 | 117 | zend_string_addref(node->path); 118 | ZVAL_STR(&zv, node->path); 119 | zend_hash_str_update(ht, "path", 4, &zv); 120 | 121 | zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &elt); 122 | } ZEND_HASH_FOREACH_END(); 123 | #else 124 | zval *elt; 125 | HashPosition pos; \ 126 | char *key; 127 | size_t keylen; 128 | char *type; 129 | 130 | for (zend_hash_internal_pointer_reset_ex(symbols, &pos) \ 131 | ;;zend_hash_move_forward_ex(symbols, &pos)) { \ 132 | if (zend_hash_has_more_elements_ex(symbols, &pos) != SUCCESS) break; 133 | node = compat_zend_hash_get_current_data_ptr_ex(symbols, &pos); 134 | compat_zend_hash_str_get_current_key_ex(symbols, &key, &keylen, NULL, 0, &pos); 135 | 136 | MAKE_STD_ZVAL(elt); 137 | array_init_size(elt, 4); 138 | 139 | type = PCS_Loader_keyTypeString(key[0]); 140 | add_assoc_string(elt, "type", type, 1); 141 | add_assoc_stringl(elt, "name", key + 1, keylen - 1, 1); 142 | 143 | mode[0] = PCS_Tree_LoadModeToDisplay(node); 144 | add_assoc_stringl(elt, "load", mode, 1, 1); 145 | add_assoc_stringl(elt, "path", ZSTR_VAL(node->path), ZSTR_LEN(node->path), 1); 146 | 147 | add_next_index_zval(return_value, elt); 148 | } 149 | #endif 150 | } 151 | } 152 | 153 | /*===============================================================*/ 154 | 155 | static zend_always_inline int MINIT_PCS_Info(TSRMLS_D) 156 | { 157 | return SUCCESS; 158 | } 159 | 160 | /*---------------------------------------------------------------*/ 161 | 162 | static zend_always_inline int MSHUTDOWN_PCS_Info(TSRMLS_D) 163 | { 164 | return SUCCESS; 165 | } 166 | 167 | /*---------------------------------------------------------------*/ 168 | 169 | static zend_always_inline int RINIT_PCS_Info(TSRMLS_D) 170 | { 171 | return SUCCESS; 172 | } 173 | /*---------------------------------------------------------------*/ 174 | 175 | static zend_always_inline int RSHUTDOWN_PCS_Info(TSRMLS_D) 176 | { 177 | return SUCCESS; 178 | } 179 | 180 | /*===============================================================*/ 181 | -------------------------------------------------------------------------------- /src/PCS_Info.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PCS extension | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2015 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt. | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Author: Francois Laupretre | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifndef __PCS_INFO_H 20 | #define __PCS_INFO_H 21 | 22 | /*============================================================================*/ 23 | 24 | static PHP_METHOD(PCS, fileCount); 25 | static PHP_METHOD(PCS, fileInfos); 26 | static PHP_METHOD(PCS, symbolInfos); 27 | 28 | /*============================================================================*/ 29 | #endif 30 | -------------------------------------------------------------------------------- /src/PCS_Loader.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PCS extension | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2015 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt. | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Author: Francois Laupretre | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifndef __PCS_LOADER_H 20 | #define __PCS_LOADER_H 21 | 22 | /*---------------------------------------------------------------*/ 23 | 24 | /* Symbol types */ 25 | 26 | #define PCS_T_CLASS 'L' 27 | #define PCS_T_FUNCTION 'F' 28 | #define PCS_T_CONSTANT 'C' 29 | 30 | /*---------------------------------------------------------------*/ 31 | 32 | static int loader_init_done = 0; 33 | 34 | static HashTable *symbols; /* (type + case-sensitive name) => (PCS_Node *) */ 35 | StaticMutexDeclare(symbols) 36 | 37 | #include "php/phpc/parser_code.phpc" 38 | 39 | static PCS_Node *StringParser_node; 40 | static PCS_Node *ParserInterface_node; 41 | 42 | static zend_string *parser_func_name; 43 | 44 | #if PHP_VERSION_ID >= 70300 45 | typedef void (ZEND_FASTCALL *pcs_zif_handler)(INTERNAL_FUNCTION_PARAMETERS); 46 | #else 47 | typedef void (*pcs_zif_handler)(INTERNAL_FUNCTION_PARAMETERS); 48 | #endif 49 | 50 | static pcs_zif_handler spl_register_handler; 51 | static pcs_zif_handler spl_unregister_handler; 52 | static pcs_zif_handler spl_functions_handler; 53 | static zend_function *pcs_autoload_func; 54 | static zend_function *spl_autoload_call_func; 55 | 56 | /*============================================================================*/ 57 | 58 | #define PCS_DECLARE_GET_REQUIRE_FUNCTIONS(_name) \ 59 | static PHP_METHOD(PCS, get ## _name); \ 60 | static PHP_METHOD(PCS, require ## _name); \ 61 | 62 | /*---------------------------------------------------------------*/ 63 | 64 | extern PHP_FUNCTION(spl_autoload_register); 65 | 66 | static PHP_FUNCTION(_pcs_autoload_register); 67 | static void PCS_Loader_insertAutoloadHook(TSRMLS_D); 68 | static PHP_FUNCTION(_pcs_autoload); 69 | static int PCS_Loader_loadSymbol(char type, char *symbol, size_t slen, zend_bool autoload 70 | , zend_bool exception TSRMLS_DC); 71 | static int PCS_Loader_symbolIsDefined(char type, char *symbol, size_t slen TSRMLS_DC); 72 | static int PCS_Loader_loadNode(PCS_Node *node, int throw TSRMLS_DC); 73 | static char *PCS_Loader_keyTypeString(char c); 74 | 75 | PCS_DECLARE_GET_REQUIRE_FUNCTIONS(Function) 76 | PCS_DECLARE_GET_REQUIRE_FUNCTIONS(Constant) 77 | PCS_DECLARE_GET_REQUIRE_FUNCTIONS(Class) 78 | 79 | static int PCS_Loader_registerNode(PCS_Node *node TSRMLS_DC); 80 | static int PCS_Loader_registerKey(zend_string *key, PCS_Node *node); 81 | static zend_function *PCS_Loader_get_function(HashTable *h, char *fname, int err); 82 | static int PCS_Loader_moduleInit(TSRMLS_D); 83 | static int PCS_Loader_Init(TSRMLS_D); 84 | 85 | /*============================================================================*/ 86 | #endif 87 | -------------------------------------------------------------------------------- /src/PCS_Stream.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PCS extension | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2015 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt. | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Author: Francois Laupretre | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | /*---------------------------------------------------------------*/ 20 | 21 | static php_stream_ops pcs_ops = { 22 | NULL, 23 | PCS_Stream_read, 24 | PCS_Stream_close, 25 | NULL, 26 | "pcs", 27 | PCS_Stream_seek, 28 | NULL, /* cast */ 29 | PCS_Stream_fstat, 30 | NULL /* set_option */ 31 | }; 32 | 33 | static php_stream_ops pcs_dirops = { 34 | NULL, /* write */ 35 | PCS_Stream_readdir, 36 | PCS_Stream_close, 37 | NULL, /* flush */ 38 | "pcs", 39 | PCS_Stream_seekdir, 40 | NULL, /* cast */ 41 | NULL, /* stat */ 42 | NULL /* set_option */ 43 | }; 44 | 45 | static php_stream_wrapper_ops pcs_stream_wops = { 46 | PCS_Stream_openfile, /* open */ 47 | NULL, /* close */ 48 | NULL, /* stat, */ 49 | PCS_Stream_url_stat, /* stat_url */ 50 | PCS_Stream_opendir, /* opendir */ 51 | "pcs", 52 | NULL, /* unlink */ 53 | NULL, /* rename */ 54 | NULL, /* mkdir */ 55 | NULL /* rmdir */ 56 | }; 57 | 58 | static php_stream_wrapper php_stream_pcs_wrapper = { 59 | &pcs_stream_wops, 60 | NULL, 61 | 0 /* is_url */ 62 | }; 63 | 64 | /*============================================================================*/ 65 | /* Allocate and intialize abstract data */ 66 | 67 | static PCS_STREAM_DATA *new_dp(int show_errors, int persistent) 68 | { 69 | PCS_STREAM_DATA *dp = NULL; 70 | 71 | PEALLOCATE(dp, sizeof(PCS_STREAM_DATA), persistent); 72 | CLEAR_DATA(*dp); 73 | dp->persistent = persistent; 74 | 75 | dp->show_errors = show_errors; 76 | 77 | return dp; 78 | } 79 | 80 | /*--------------------*/ 81 | /* Free abstract data */ 82 | 83 | static void free_dp(PCS_STREAM_DATA **dpp) 84 | { 85 | PCS_STREAM_DATA *dp; 86 | 87 | if ((!dpp) || (!(dp = *dpp))) { 88 | return; 89 | } 90 | 91 | PEFREE(dp, dp->persistent); 92 | } 93 | 94 | /*--------------------*/ 95 | /* File read */ 96 | 97 | static size_t PCS_Stream_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) 98 | { 99 | size_t max; 100 | PCS_STREAM_DATA *dp = stream->abstract; 101 | 102 | ZEND_ASSERT(PCS_NODE_IS_FILE(dp->node)); 103 | 104 | max = PCS_FILE_LEN(dp->node) - dp->offset; 105 | if (max < 0) max = 0; /* Should not happen */ 106 | if (count > max) count = max; 107 | 108 | if (count) { 109 | memmove(buf, PCS_FILE_DATA(dp->node) + dp->offset, count); 110 | } 111 | 112 | dp->offset += count; 113 | stream->eof = (PCS_FILE_LEN(dp->node) == dp->offset); 114 | 115 | return count; 116 | } 117 | 118 | /*--------------------*/ 119 | /* Close a file or a directory */ 120 | 121 | static int PCS_Stream_close(php_stream *stream, int close_handle TSRMLS_DC) 122 | { 123 | PCS_STREAM_DATA *dp = stream->abstract; 124 | 125 | free_dp(&dp); 126 | 127 | return 0; 128 | } 129 | 130 | /*--------------------*/ 131 | /* File seek */ 132 | /* Warning: zend_off_t is signed but size_t is not. (zend_off_t) casts below are 133 | mandatory for signed operations. */ 134 | 135 | static int PCS_Stream_seek(php_stream *stream, zend_off_t offset, int whence 136 | , zend_off_t *newoffset TSRMLS_DC) 137 | { 138 | PCS_STREAM_DATA *dp = stream->abstract; 139 | 140 | ZEND_ASSERT(PCS_NODE_IS_FILE(dp->node)); 141 | /*DBG_MSG3("start: dp->offset=%d, offset=%d, whence=%d\n",dp->offset,offset,whence);*/ 142 | 143 | switch (whence) { 144 | case SEEK_SET: 145 | dp->offset = offset; 146 | break; 147 | 148 | case SEEK_CUR: 149 | dp->offset += offset; 150 | break; 151 | 152 | 153 | case SEEK_END: 154 | dp->offset = (zend_off_t)PCS_FILE_LEN(dp->node) + offset; 155 | break; 156 | } 157 | 158 | if (dp->offset > (zend_off_t)PCS_FILE_LEN(dp->node)) dp->offset = PCS_FILE_LEN(dp->node); 159 | if (dp->offset < 0) dp->offset = (zend_off_t)0; 160 | 161 | if (newoffset) (*newoffset) = dp->offset; 162 | stream->eof = (dp->offset == (zend_off_t)PCS_FILE_LEN(dp->node)); 163 | 164 | /*DBG_MSG2("end: offset=%d, stream->eof=%d\n",dp->offset,stream->eof);*/ 165 | return 0; 166 | } 167 | 168 | /*--------------------*/ 169 | 170 | static PCS_Node *PCS_Stream_getNodeFromURI(const char *uri, size_t len) 171 | { 172 | PCS_Node *node; 173 | 174 | ZEND_ASSERT(uri); 175 | DBG_MSG1("-> PCS_Stream_getNodeFromURI(%s)", uri); 176 | 177 | if (len < 6) return NULL; 178 | node = PCS_Tree_getNodeFromPath(uri + 6, len - 6); 179 | if (! node) { 180 | DBG_MSG1("*** PCS_Stream_getNodeFromURI(%s) failed", uri); 181 | } else { 182 | DBG_MSG2("<- PCS_Stream_getNodeFromURI(%s) => %s", uri, ZSTR_VAL(node->path)); 183 | } 184 | 185 | return node; 186 | } 187 | 188 | /*--------------------*/ 189 | /* Stat on a file or dir (opened or not) */ 190 | 191 | static int do_stat(php_stream_wrapper *wrapper, const char *uri 192 | , PCS_STREAM_DATA *dp, php_stream_statbuf *ssb TSRMLS_DC) 193 | { 194 | DBG_MSG1("-> do_stat(%s)", uri); 195 | 196 | /*-- Get node */ 197 | 198 | if (!(dp->node)) { 199 | dp->node = PCS_Stream_getNodeFromURI(uri, (size_t)strlen(uri)); 200 | if (!(dp->node)) { 201 | php_stream_wrapper_log_error(wrapper, dp->show_errors TSRMLS_CC 202 | , "%s: File not found", uri); 203 | return -1; 204 | } 205 | } 206 | 207 | memset(ssb, 0, sizeof(*ssb)); 208 | 209 | ssb->sb.st_size = (off_t)(PCS_NODE_IS_DIR(dp->node) 210 | ? zend_hash_num_elements(PCS_DIR_HT(dp->node)) : PCS_FILE_LEN(dp->node)); 211 | ssb->sb.st_mode = (mode_t) (PCS_NODE_IS_DIR(dp->node) ? S_IFDIR|0555 : S_IFREG|0444); 212 | ssb->sb.st_nlink = 1; 213 | #ifdef HAVE_ST_RDEV 214 | ssb->sb.st_rdev = -1; 215 | #endif 216 | #ifdef HAVE_ST_BLKSIZE 217 | ssb->sb.st_blksize = -1; 218 | #endif 219 | #ifdef HAVE_ST_BLOCKS 220 | ssb->sb.st_blocks = -1; 221 | #endif 222 | 223 | DBG_MSG("<- do_stat()"); 224 | return 0; 225 | } 226 | 227 | /*--------------------*/ 228 | /* Stat on an open file/dir */ 229 | 230 | static int PCS_Stream_fstat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC) 231 | { 232 | PCS_STREAM_DATA *dp = stream->abstract; 233 | 234 | if (!ssb) return -1; 235 | 236 | return do_stat(stream->wrapper, stream->orig_path, dp, ssb TSRMLS_CC); 237 | } 238 | 239 | /*---------------------------------------------------------------*/ 240 | /* readdir */ 241 | 242 | static size_t PCS_Stream_readdir(php_stream *stream, char *buf, size_t count TSRMLS_DC) 243 | { 244 | php_stream_dirent *ent = (php_stream_dirent *) buf; 245 | PCS_STREAM_DATA *dp = stream->abstract; 246 | HashTable *ht; 247 | char *name; 248 | size_t nlen; 249 | 250 | ZEND_ASSERT(PCS_NODE_IS_DIR(dp->node)); 251 | 252 | ht = PCS_DIR_HT(dp->node); 253 | 254 | if (compat_zend_hash_str_get_current_key_ex(ht, &name, &nlen, NULL, 0 255 | , &(dp->pos)) == HASH_KEY_NON_EXISTENT) { 256 | stream->eof = 1; 257 | return 0; 258 | } 259 | 260 | count = MIN((size_t)sizeof(ent->d_name) - 1, nlen); 261 | memmove(ent->d_name, name, count); 262 | ent->d_name[count] = '\0'; 263 | 264 | zend_hash_move_forward_ex(ht, &(dp->pos)); 265 | stream->eof = (zend_hash_has_more_elements_ex(ht, &(dp->pos)) == FAILURE); 266 | 267 | return sizeof(php_stream_dirent); 268 | } 269 | 270 | /*--------------------*/ 271 | /* rewinddir */ 272 | 273 | static int PCS_Stream_seekdir(php_stream *stream, zend_off_t offset 274 | , int whence, zend_off_t *newoffset TSRMLS_DC) 275 | { 276 | PCS_STREAM_DATA *dp = stream->abstract; 277 | HashTable *ht; 278 | 279 | ZEND_ASSERT(PCS_NODE_IS_DIR(dp->node)); 280 | 281 | ht = PCS_DIR_HT(dp->node); 282 | if ((whence == SEEK_SET) && (!offset)) { /* rewinddir */ 283 | zend_hash_internal_pointer_reset_ex(ht, &(dp->pos)); 284 | stream->eof = (zend_hash_has_more_elements_ex(ht, &(dp->pos)) == SUCCESS); 285 | if (newoffset) (*newoffset) = (zend_off_t)0; 286 | return 0; 287 | } 288 | 289 | return -1; 290 | } 291 | 292 | /*---------------------------------------------------------------*/ 293 | /* Used to open a file or a directory */ 294 | /* Support persistent streams */ 295 | 296 | #define ABORT_PCS_STREAM_OPEN() \ 297 | { \ 298 | DBG_MSG("<** Aborting generic_open()"); \ 299 | free_dp(&dp); \ 300 | EFREE(persistent_id); \ 301 | return NULL; \ 302 | } 303 | 304 | static php_stream *PCS_Stream_generic_open(int dir, php_stream_wrapper *wrapper 305 | , const char *uri, const char *mode, int options, OPENED_PATH_PTR *opened_path 306 | , php_stream_context *context STREAMS_DC TSRMLS_DC) 307 | { 308 | PCS_STREAM_DATA *dp = NULL; 309 | size_t uri_len; 310 | char open_flags; 311 | php_stream *ret; 312 | int persistent = options & STREAM_OPEN_PERSISTENT; 313 | char *persistent_id = NULL; 314 | 315 | DBG_MSG2("-> generic_open(%s %s)", (dir ? "dir" : "file"), uri); 316 | 317 | uri_len = (size_t)strlen(uri); 318 | 319 | /*-- For files, support read mode only ('r' or 'rb') */ 320 | 321 | if ((!dir) && ((mode[0] != 'r') || (mode[1] && mode[1] != 'b'))) { 322 | php_stream_wrapper_log_error(wrapper, options TSRMLS_CC 323 | , "'%s' mode not supported (read-only access)", mode); 324 | ABORT_PCS_STREAM_OPEN(); 325 | } 326 | open_flags = (((!dir) && (mode[1] == 'b')) ? 'b' : 't'); 327 | 328 | /*-- Allocate the private ('abstract') data */ 329 | 330 | dp = new_dp(options & REPORT_ERRORS, persistent); 331 | 332 | /*-- Get node */ 333 | 334 | dp->node = PCS_Stream_getNodeFromURI(uri, uri_len); 335 | if (!(dp->node)) 336 | { 337 | php_stream_wrapper_log_error(wrapper, options TSRMLS_CC 338 | , "%s: File not found", uri); 339 | ABORT_PCS_STREAM_OPEN(); 340 | } 341 | 342 | /* Check node type */ 343 | 344 | if (dir && (!PCS_NODE_IS_DIR(dp->node))) { 345 | php_stream_wrapper_log_error(wrapper, options TSRMLS_CC 346 | , "%s: Node is not a directory", uri); 347 | ABORT_PCS_STREAM_OPEN(); 348 | } 349 | if ((!dir) && (!PCS_NODE_IS_FILE(dp->node))) { 350 | php_stream_wrapper_log_error(wrapper, options TSRMLS_CC 351 | , "%s: Node is not a regular file", uri); 352 | ABORT_PCS_STREAM_OPEN(); 353 | } 354 | 355 | /*-- Persitent open */ 356 | 357 | if (persistent) { 358 | spprintf(&persistent_id, 0, "streams_pcs_%c_%s", open_flags 359 | , ZSTR_VAL(dp->node->path)); 360 | switch (php_stream_from_persistent_id(persistent_id, &ret TSRMLS_CC)) { 361 | case PHP_STREAM_PERSISTENT_SUCCESS: 362 | if (opened_path) { 363 | #ifdef PHP_7 364 | zend_string_addref(dp->node->uri); 365 | (*opened_path) = dp->node->uri; 366 | #else 367 | (*opened_path) = ut_eduplicate(ZSTR_VAL(dp->node->uri) 368 | , ZSTR_LEN(dp->node->uri) + 1); 369 | #endif 370 | } 371 | /* fall through */ 372 | case PHP_STREAM_PERSISTENT_FAILURE: 373 | EFREE(persistent_id);; 374 | return ret; 375 | /* Default: PHP_STREAM_PERSISTENT_NOT_EXIST => Continue */ 376 | } 377 | } 378 | 379 | /* Init dp data */ 380 | 381 | if (dir) { 382 | zend_hash_internal_pointer_reset_ex(PCS_DIR_HT(dp->node), &(dp->pos)); 383 | } else { /* File */ 384 | dp->offset = 0; /*-- Initialize offset */ 385 | } 386 | 387 | if (opened_path) { /* Return canonical path as opened path */ 388 | #ifdef PHP_7 389 | zend_string_addref(dp->node->uri); 390 | (*opened_path) = dp->node->uri; 391 | #else 392 | (*opened_path) = ut_eduplicate(ZSTR_VAL(dp->node->uri) 393 | , ZSTR_LEN(dp->node->uri) + 1); 394 | #endif 395 | } 396 | 397 | DBG_MSG("<- generic_open()"); 398 | ret = php_stream_alloc((dir ? &pcs_dirops : &pcs_ops), dp, persistent_id, mode); 399 | 400 | EFREE(persistent_id); 401 | return ret; 402 | } 403 | 404 | /*--------------------*/ 405 | 406 | static php_stream *PCS_Stream_openfile(php_stream_wrapper *wrapper 407 | , COMPAT_STREAM_CONST_DECL char *uri, COMPAT_STREAM_CONST_DECL char *mode, int options 408 | , OPENED_PATH_PTR *opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC) 409 | { 410 | return PCS_Stream_generic_open(0, wrapper, uri, mode, options 411 | , opened_path, context STREAMS_CC TSRMLS_CC); 412 | } 413 | 414 | /*---------------------------------------------------------------*/ 415 | 416 | static int PCS_Stream_url_stat(php_stream_wrapper *wrapper, COMPAT_STREAM_CONST_DECL char *uri 417 | , int flags, php_stream_statbuf *ssb, php_stream_context *context TSRMLS_DC) 418 | { 419 | PCS_STREAM_DATA *dp; 420 | int retval; 421 | 422 | dp = new_dp((flags & PHP_STREAM_URL_STAT_QUIET) ? 0 : REPORT_ERRORS, 0); 423 | retval = do_stat(wrapper, uri, dp, ssb TSRMLS_CC); 424 | free_dp(&dp); 425 | 426 | return retval; 427 | } 428 | 429 | /*--------------------*/ 430 | 431 | static php_stream *PCS_Stream_opendir(php_stream_wrapper * wrapper 432 | , COMPAT_STREAM_CONST_DECL char *uri, COMPAT_STREAM_CONST_DECL char *mode, int options 433 | , OPENED_PATH_PTR *opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC) 434 | { 435 | return PCS_Stream_generic_open(1, wrapper, uri, mode, options 436 | , opened_path, context STREAMS_CC TSRMLS_CC); 437 | } 438 | 439 | /*---------------------------------------------------------------*/ 440 | /* Module initialization */ 441 | 442 | static zend_always_inline int MINIT_PCS_Stream(TSRMLS_D) 443 | { 444 | php_register_url_stream_wrapper("pcs", &php_stream_pcs_wrapper TSRMLS_CC); 445 | 446 | return SUCCESS; 447 | } 448 | 449 | /*---------------------------------------------------------------*/ 450 | /* Module shutdown */ 451 | 452 | static zend_always_inline int MSHUTDOWN_PCS_Stream(TSRMLS_D) 453 | { 454 | php_unregister_url_stream_wrapper("pcs" TSRMLS_CC); 455 | 456 | return SUCCESS; 457 | } 458 | 459 | /*---------------------------------------------------------------*/ 460 | 461 | static zend_always_inline int RINIT_PCS_Stream(TSRMLS_D) 462 | { 463 | return SUCCESS; 464 | } 465 | 466 | /*---------------------------------------------------------------*/ 467 | 468 | static zend_always_inline int RSHUTDOWN_PCS_Stream(TSRMLS_D) 469 | { 470 | return SUCCESS; 471 | } 472 | 473 | /*---------------------------------------------------------------*/ 474 | -------------------------------------------------------------------------------- /src/PCS_Stream.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PCS extension | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2015 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt. | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Author: Francois Laupretre | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifndef __PCS_STREAM_H 20 | #define __PCS_STREAM_H 21 | 22 | #include "Zend/zend_hash.h" 23 | 24 | /*============================================================================*/ 25 | 26 | typedef struct { 27 | int persistent; 28 | zend_off_t offset; 29 | int show_errors; 30 | PCS_Node *node; 31 | HashPosition pos; /* readdir() position */ 32 | } PCS_STREAM_DATA; 33 | 34 | /*----------------------------------------*/ 35 | 36 | #define PCS_DP_FILE_DATA(_dp) (_dp)->node.u.f.data 37 | #define PCS_DP_FILE_LEN(_dp) (_dp)->node.u.f.len 38 | #define PCS_DP_DIR_HT(_dp) (_dp)->node.u.d.items 39 | 40 | /*============================================================================*/ 41 | 42 | static PCS_STREAM_DATA *new_dp(int show_errors, int persistent); 43 | static void free_dp(PCS_STREAM_DATA **dpp); 44 | static size_t PCS_Stream_read(php_stream *stream, char *buf, size_t count TSRMLS_DC); 45 | static int PCS_Stream_close(php_stream *stream, int close_handle TSRMLS_DC); 46 | static int PCS_Stream_seek(php_stream *stream, zend_off_t offset, int whence, zend_off_t *newoffset TSRMLS_DC); 47 | static PCS_Node *PCS_Stream_getNodeFromURI(const char *uri, size_t len); 48 | static int do_stat(php_stream_wrapper *wrapper, const char *uri, PCS_STREAM_DATA *dp, php_stream_statbuf *ssb TSRMLS_DC); 49 | static int PCS_Stream_fstat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC); 50 | static size_t PCS_Stream_readdir(php_stream *stream, char *buf, size_t count TSRMLS_DC); 51 | static int PCS_Stream_seekdir(php_stream *stream, zend_off_t offset, int whence, zend_off_t *newoffset TSRMLS_DC); 52 | static php_stream *PCS_Stream_generic_open(int dir, php_stream_wrapper *wrapper, const char *uri, const char *mode, int options, OPENED_PATH_PTR *opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC); 53 | static php_stream *PCS_Stream_openfile(php_stream_wrapper * wrapper, COMPAT_STREAM_CONST_DECL char *uri, COMPAT_STREAM_CONST_DECL char *mode, int options, OPENED_PATH_PTR *opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC); 54 | static int PCS_Stream_url_stat(php_stream_wrapper *wrapper, COMPAT_STREAM_CONST_DECL char *uri, int flags, php_stream_statbuf *ssb, php_stream_context *context TSRMLS_DC); 55 | static php_stream *PCS_Stream_opendir(php_stream_wrapper * wrapper, COMPAT_STREAM_CONST_DECL char *uri, COMPAT_STREAM_CONST_DECL char *mode, int options, OPENED_PATH_PTR *opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC); 56 | 57 | /*============================================================================*/ 58 | #endif 59 | -------------------------------------------------------------------------------- /src/PCS_Tree.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PCS extension | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2005-2015 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt. | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Author: Francois Laupretre | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #include 20 | #include "php_streams.h" 21 | #include "ext/standard/php_filestat.h" 22 | 23 | /*---------------------------------------------------------------*/ 24 | /* Add a subnode to an existing directory node 25 | 26 | Note: 27 | - File data is not initialized. 28 | - Adding an already-existing subdir is OK. 29 | - name arg doesn't have to be null-terminated. 30 | - '.' and '..' are forbidden as node name 31 | - Null 'parent' means we are creating the root node 32 | - On error, returns NULL 33 | */ 34 | 35 | static PCS_Node *PCS_Tree_addSubNode(PCS_Node *parent, const char *name 36 | , size_t len, int type, zend_ulong flags) 37 | { 38 | PCS_Node *node; 39 | char *p; 40 | 41 | ZEND_ASSERT(!(parent && (len <= 0))); /* Accept empty name for root only */ 42 | 43 | if ((len <= 2) && (name[0]=='.') && ((name[1]=='.') || (len == 1))) { 44 | php_error(E_CORE_ERROR, "Cannot create node named '.' or '..'"); 45 | return NULL; 46 | } 47 | 48 | /* Check if entry already exists */ 49 | 50 | if (parent) { 51 | node = (PCS_Node *)zend_hash_str_find_ptr(PCS_DIR_HT(parent), name, len); 52 | if (node) { 53 | if (PCS_NODE_IS_DIR(node)) { 54 | if (type == PCS_TYPE_DIR) { 55 | return node; /* Dir exists already, return it */ 56 | } else { 57 | php_error(E_CORE_ERROR 58 | ,"%s: Cannot create file, a directory with that name does already exist" 59 | , ZSTR_VAL(node->path) 60 | ); 61 | return NULL; 62 | } 63 | } else { /* Existing node is a file -> error */ 64 | php_error(E_CORE_ERROR 65 | ,"%s: Cannot create %s, a file with that name does already exist" 66 | , ZSTR_VAL(node->path) 67 | , ((type == PCS_TYPE_DIR) ? "dir" : "file")); 68 | return NULL; 69 | } 70 | } 71 | } 72 | 73 | /* Create node (type-common) */ 74 | 75 | node = ut_pallocate(NULL, sizeof(PCS_Node)); 76 | CLEAR_DATA(*node); 77 | 78 | node->parent = parent; 79 | node->type = type; 80 | node->flags = flags; 81 | 82 | if (parent) { 83 | node->path = zend_string_alloc(ZSTR_LEN(parent->path) + 1 + len, 1); 84 | p = ZSTR_VAL(node->path); 85 | if (PCS_NODE_IS_ROOT(parent)) { 86 | ZSTR_LEN(node->path) = len; 87 | } else { 88 | memcpy(p, ZSTR_VAL(parent->path), ZSTR_LEN(parent->path)); 89 | p += ZSTR_LEN(parent->path); 90 | (*(p++)) = '/'; 91 | } 92 | memcpy(p, name, len); 93 | p[len] = '\0'; 94 | } else { /* Root node */ 95 | node->path = zend_string_init("", 0, 1); 96 | } 97 | zend_string_hash_val(node->path); 98 | 99 | node->uri = zend_string_alloc(ZSTR_LEN(node->path) + 6, 1); 100 | sprintf(ZSTR_VAL(node->uri), "pcs://%s", ZSTR_VAL(node->path)); 101 | zend_string_hash_val(node->uri); 102 | 103 | /* Record path in pathList (increments zend_string refcount) */ 104 | 105 | MutexLock(pathList); 106 | zend_hash_add_new_ptr(pathList, node->path, node); 107 | MutexUnlock(pathList); 108 | 109 | /* Add node to parent's subnode list */ 110 | 111 | if (parent) { 112 | zend_hash_str_add_new_ptr(PCS_DIR_HT(parent), name, len, node); 113 | } 114 | 115 | /* Type-specific init */ 116 | 117 | switch (type) { 118 | case PCS_TYPE_DIR: 119 | zend_hash_init(PCS_DIR_HT(node), 8, 0, (dtor_func_t)PCS_Tree_destroyNode, 1); 120 | break; 121 | 122 | case PCS_TYPE_FILE: 123 | node->u.f.id = zend_hash_next_free_element(fileList); 124 | zend_hash_next_index_insert_ptr(fileList, node); 125 | break; 126 | } 127 | 128 | return node; 129 | } 130 | 131 | /*--------------------*/ 132 | /* On error, returns NULL */ 133 | 134 | static PCS_Node *PCS_Tree_addNode(const char *path, size_t path_len 135 | , int type, zend_ulong flags) 136 | { 137 | PCS_Node *node; 138 | size_t remaining, len; 139 | const char *start, *found; 140 | zend_string *cpath; 141 | 142 | cpath = PCS_Tree_cleanPath(path, path_len); 143 | start = ZSTR_VAL(cpath); 144 | node = root; 145 | while (1) { 146 | remaining = ZSTR_LEN(cpath) - (size_t)(start - ZSTR_VAL(cpath)); 147 | found = memchr(start, '/', remaining); 148 | len = (found ? (size_t)(found - start) : remaining); 149 | node = PCS_Tree_addSubNode(node, start, len, (found ? PCS_TYPE_DIR : type) 150 | , flags); 151 | if (! node) return NULL; 152 | if (! found) break; 153 | start = found + 1; 154 | } 155 | 156 | zend_string_release(cpath); 157 | return node; 158 | } 159 | 160 | /*--------------------*/ 161 | 162 | static PCS_Node *PCS_Tree_addDir(const char *path, size_t path_len, zend_ulong flags) 163 | { 164 | return PCS_Tree_addNode(path, path_len, PCS_TYPE_DIR, flags); 165 | } 166 | 167 | /*--------------------*/ 168 | 169 | static PCS_Node *PCS_Tree_addFile(const char *path, size_t path_len 170 | , char *data, size_t datalen, int alloc, zend_ulong flags) 171 | { 172 | PCS_Node *node; 173 | 174 | node = PCS_Tree_addNode(path, path_len, PCS_TYPE_FILE, flags); 175 | if (! node) return NULL; 176 | 177 | node->u.f.data = data; 178 | node->u.f.len = datalen; 179 | node->u.f.alloc = alloc; 180 | 181 | return node; 182 | } 183 | 184 | /*--------------------*/ 185 | 186 | static void PCS_Tree_destroyNode(zval *zp) 187 | { 188 | PCS_Node **nodep, *node; 189 | 190 | nodep = (PCS_Node **)COMPAT_HASH_PTR(zp); 191 | node = *nodep; 192 | 193 | #if ZEND_DEBUG 194 | node->flags |= PCS_FLAG_NOCHECK; /* Checks will fail during tree destruction */ 195 | #endif 196 | 197 | zend_string_release(node->path); 198 | zend_string_release(node->uri); 199 | 200 | if (PCS_NODE_IS_DIR(node)) { 201 | zend_hash_destroy(PCS_DIR_HT(node)); 202 | } else { 203 | if (PCS_FILE_ALLOC(node)) { 204 | ut_pallocate(PCS_FILE_DATA(node), 0); 205 | } 206 | } 207 | 208 | PFREE(*nodep); /* Security: free and set null ptr */ 209 | } 210 | 211 | /*--------------------*/ 212 | /* Returns a newly-allocated string (must be released by caller) 213 | Replace '\' with '/' 214 | Remove leading and trailing '/', multiple '/' 215 | Note : 'name' input arg does not have to be null-terminated. 216 | */ 217 | 218 | static zend_string *PCS_Tree_cleanPath(const char *path, size_t len) 219 | { 220 | size_t dlen, remain; 221 | int ignore_slash; 222 | zend_string *ret; 223 | char *target, c; 224 | 225 | ret = zend_string_alloc(len, 0); 226 | target = ZSTR_VAL(ret); 227 | for(ignore_slash = 1, remain = len ; remain ; path++, remain--) { 228 | c = (*path); 229 | if (c == '\\') c = '/'; 230 | if (c == '/') { 231 | if (ignore_slash) { 232 | continue; 233 | } else { 234 | ignore_slash = 1; 235 | } 236 | } else { 237 | ignore_slash = 0; 238 | } 239 | *(target++) = c; 240 | } 241 | dlen = (size_t)(target - ZSTR_VAL(ret)); 242 | target--; 243 | while (dlen && ((*target) == '/')) { 244 | dlen--; 245 | target--; 246 | } 247 | *(target + 1) = '\0'; 248 | 249 | ZSTR_LEN(ret) = dlen; 250 | return ret; 251 | } 252 | 253 | /*--------------------*/ 254 | /* Resolve a path not existing in pathList 255 | On entry, path is 'clean', ie produced by PCS_Tree_cleanPath() 256 | Handles '.' and '..' special dir entries 257 | Returns NULL if node does not exist 258 | */ 259 | 260 | static PCS_Node *PCS_Tree_resolvePath(zend_string *path) 261 | { 262 | PCS_Node *node; 263 | size_t remaining, len; 264 | char *start, *end; 265 | 266 | DBG_MSG1("-> PCS_Tree_resolvePath(%s)", ZSTR_VAL(path)); 267 | 268 | node = root; 269 | start = ZSTR_VAL(path); 270 | while (1) { 271 | remaining = ZSTR_LEN(path) - (size_t)(start - ZSTR_VAL(path)); 272 | end = memchr(start, '/', remaining); 273 | len = (end ? (size_t)(end - start) : remaining); 274 | if ((len == 2) && (start[0] == '.') && (start[1] == '.')) { 275 | if (node->parent) { 276 | node = node->parent; 277 | } 278 | } else if ((len != 1) || (start[0] != '.')) { 279 | /* '.' remains on the same node */ 280 | node = zend_hash_str_find_ptr(PCS_DIR_HT(node), start 281 | , (end ? len : remaining)); 282 | } 283 | if ((!end) || (!node)) break; 284 | if (! PCS_NODE_IS_DIR(node)) return NULL; 285 | start = end + 1; 286 | } 287 | DBG_MSG("<- PCS_Tree_resolvePath()"); 288 | return node; 289 | } 290 | 291 | /*--------------------*/ 292 | /* If path is valid but not in pathList, add it using the mutex */ 293 | 294 | static PCS_Node *PCS_Tree_getNodeFromPath(const char *path, size_t len) 295 | { 296 | zend_string *cpath, *pcpath; 297 | PCS_Node *node; 298 | 299 | DBG_MSG1("-> PCS_Tree_getNodeFromPath(%s)", path); 300 | 301 | cpath = PCS_Tree_cleanPath(path, len); 302 | 303 | if (UNEXPECTED(!ZSTR_LEN(cpath))) { 304 | node = root; 305 | } else { 306 | node = zend_hash_find_ptr(pathList, cpath); 307 | if (!node) { 308 | node = PCS_Tree_resolvePath(cpath); 309 | if (node) { /* Register unknown path in path list */ 310 | DBG_MSG1("%s: Registering path in pathList", ZSTR_VAL(cpath)); 311 | MutexLock(pathList); 312 | pcpath = zend_string_dup(cpath, 1); /* Make persistent */ 313 | zend_hash_add_new_ptr(pathList, pcpath, node); 314 | MutexUnlock(pathList); 315 | } 316 | } 317 | } 318 | 319 | zend_string_release(cpath); 320 | return node; 321 | } 322 | 323 | /*--------------------*/ 324 | 325 | static PCS_Node *PCS_Tree_getNodeFromID(PCS_ID id) 326 | { 327 | return zend_hash_index_find_ptr(fileList, (zend_ulong)id); 328 | } 329 | 330 | /*--------------------*/ 331 | 332 | static char PCS_Tree_LoadModeToDisplay(const PCS_Node *node) 333 | { 334 | char *modes="!AR-"; 335 | 336 | return modes[node->load_mode & PCS_LOAD_MASK]; 337 | } 338 | 339 | /*===============================================================*/ 340 | 341 | static zend_always_inline int MINIT_PCS_Tree(TSRMLS_D) 342 | { 343 | /* Init path list */ 344 | /* No destructor because PCS_Node structs are destroyed with the tree */ 345 | 346 | MutexSetup(pathList); 347 | pathList = ut_pallocate(NULL, sizeof(*pathList)); 348 | zend_hash_init(pathList, 32, 0, NULL, 1); 349 | 350 | /* Init file list */ 351 | 352 | fileList = ut_pallocate(NULL, sizeof(*fileList)); 353 | zend_hash_init(fileList, 32, 0, NULL, 1); 354 | 355 | /* Create root node */ 356 | 357 | root = PCS_Tree_addSubNode(NULL, "", 0, PCS_TYPE_DIR, 0); 358 | 359 | return SUCCESS; 360 | } 361 | 362 | /*---------------------------------------------------------------*/ 363 | 364 | static zend_always_inline int MSHUTDOWN_PCS_Tree(TSRMLS_D) 365 | { 366 | 367 | /* Free path list */ 368 | 369 | zend_hash_destroy(pathList); 370 | PFREE(pathList); 371 | MutexShutdown(pathList); 372 | 373 | /* Free file list */ 374 | 375 | zend_hash_destroy(fileList); 376 | PFREE(fileList); 377 | 378 | /* Destroy tree */ 379 | 380 | #ifdef PHP_7 381 | { 382 | zval zv; 383 | 384 | ZVAL_PTR(&zv, root); 385 | PCS_Tree_destroyNode(&zv); 386 | root = NULL; 387 | } 388 | #else 389 | PCS_Tree_destroyNode((zval *)(&root)); 390 | #endif 391 | 392 | return SUCCESS; 393 | } 394 | 395 | /*---------------------------------------------------------------*/ 396 | 397 | static zend_always_inline int RINIT_PCS_Tree(TSRMLS_D) 398 | { 399 | return SUCCESS; 400 | } 401 | /*---------------------------------------------------------------*/ 402 | 403 | static zend_always_inline int RSHUTDOWN_PCS_Tree(TSRMLS_D) 404 | { 405 | return SUCCESS; 406 | } 407 | 408 | /*===============================================================*/ 409 | -------------------------------------------------------------------------------- /src/PCS_Tree.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PCS extension | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2015 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt. | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Author: Francois Laupretre | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifndef __PCS_TREE_H 20 | #define __PCS_TREE_H 21 | 22 | /*---------------------------------------------------------------*/ 23 | 24 | /* Node types */ 25 | 26 | #define PCS_TYPE_DIR 0 27 | #define PCS_TYPE_FILE 1 28 | 29 | #define PCS_NODE_IS_DIR(np) ((np)->type == PCS_TYPE_DIR) 30 | #define PCS_NODE_IS_FILE(np) ((np)->type == PCS_TYPE_FILE) 31 | 32 | /* For flag definitions, see client include file */ 33 | 34 | /* Unpublished - used internally to avoid valgrind errors in debug mode */ 35 | 36 | #define PCS_FLAG_NOCHECK 0x04 /* Avoids valgrind errors in debug mode */ 37 | 38 | /*---*/ 39 | 40 | #define PCS_NODE_IS_ROOT(_np) ((_np) == root) 41 | 42 | /*---*/ 43 | 44 | struct _PCS_Node { 45 | struct _PCS_Node *parent; 46 | int type; 47 | zend_ulong flags; 48 | zend_ulong load_mode; /* Explicit or chosen mode (!= 0) */ 49 | zend_string *path; 50 | zend_string *uri; 51 | union { 52 | struct { 53 | char *data; 54 | size_t len; 55 | int alloc; 56 | zend_ulong id; 57 | } f; 58 | struct { 59 | HashTable items; /* => (PCS_Node *) (ptr) */ 60 | } d; 61 | } u; 62 | }; 63 | 64 | typedef struct _PCS_Node PCS_Node; 65 | 66 | /*---------------------------------------------------------------*/ 67 | /* Persistent data */ 68 | /* We don't set mutexes on elements which cannot be modified after MINIT. */ 69 | 70 | static PCS_Node *root; /* Root dir */ 71 | 72 | static HashTable *pathList; /* path => (PCS_Node *) (ptr) */ 73 | StaticMutexDeclare(pathList) 74 | 75 | static HashTable *fileList; /* list of file nodes (index = file id) */ 76 | 77 | /*---------------------------------------------------------------*/ 78 | 79 | #if ZEND_DEBUG 80 | static void PCS_CHECK_NODE(PCS_Node *node) 81 | { 82 | ZEND_ASSERT(node); 83 | if (! (node->flags & PCS_FLAG_NOCHECK)) { 84 | if (node->parent) { 85 | PCS_CHECK_NODE(node->parent); 86 | ZEND_ASSERT(PCS_NODE_IS_DIR(node->parent)); 87 | } 88 | CHECK_ZSTRING(node->path); 89 | CHECK_ZSTRING(node->uri); 90 | /* load_mode is null between MINIT and first Loader init */ 91 | ZEND_ASSERT(node->load_mode <= PCS_LOAD_MASK); 92 | } 93 | } 94 | #else 95 | #define PCS_CHECK_NODE(node) 96 | #endif 97 | 98 | /*------*/ 99 | 100 | static zend_always_inline char *PCS_FILE_DATA(PCS_Node *node) 101 | { 102 | PCS_CHECK_NODE(node); 103 | ZEND_ASSERT(PCS_NODE_IS_FILE(node)); 104 | return node->u.f.data; 105 | } 106 | 107 | /*------*/ 108 | 109 | static zend_always_inline size_t PCS_FILE_LEN(PCS_Node *node) 110 | { 111 | PCS_CHECK_NODE(node); 112 | ZEND_ASSERT(PCS_NODE_IS_FILE(node)); 113 | return node->u.f.len; 114 | } 115 | 116 | /*------*/ 117 | 118 | static zend_always_inline int PCS_FILE_ALLOC(PCS_Node *node) 119 | { 120 | PCS_CHECK_NODE(node); 121 | ZEND_ASSERT(PCS_NODE_IS_FILE(node)); 122 | return node->u.f.alloc; 123 | } 124 | 125 | /*------*/ 126 | 127 | static zend_always_inline zend_ulong PCS_FILE_ID(PCS_Node *node) 128 | { 129 | PCS_CHECK_NODE(node); 130 | ZEND_ASSERT(PCS_NODE_IS_FILE(node)); 131 | return node->u.f.id; 132 | } 133 | 134 | /*------*/ 135 | 136 | static zend_always_inline HashTable *PCS_DIR_HT(PCS_Node *node) 137 | { 138 | PCS_CHECK_NODE(node); 139 | ZEND_ASSERT(PCS_NODE_IS_DIR(node)); 140 | return &(node->u.d.items); 141 | } 142 | 143 | /*============================================================================*/ 144 | 145 | static PCS_Node *PCS_Tree_addSubNode(PCS_Node *parent, const char *name 146 | , size_t len, int type, zend_ulong flags); 147 | static PCS_Node *PCS_Tree_addNode(const char *path, size_t path_len 148 | , int type, zend_ulong flags); 149 | static PCS_Node *PCS_Tree_addDir(const char *path, size_t path_len, zend_ulong flags); 150 | static PCS_Node *PCS_Tree_addFile(const char *path, size_t path_len 151 | , char *data, size_t datalen, int alloc, zend_ulong flags); 152 | static void PCS_Tree_destroyNode(zval *zp); 153 | static zend_string *PCS_Tree_cleanPath(const char *path, size_t len); 154 | static PCS_Node *PCS_Tree_resolvePath(zend_string *path); 155 | static PCS_Node *PCS_Tree_getNodeFromPath(const char *path, size_t len); 156 | static PCS_Node *PCS_Tree_getNodeFromID(PCS_ID id); 157 | static char PCS_Tree_LoadModeToDisplay(const PCS_Node *node); 158 | 159 | /*============================================================================*/ 160 | #endif 161 | -------------------------------------------------------------------------------- /src/PCS_Utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PCS extension | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2005-2015 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt. | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Author: Francois Laupretre | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | /*---------------------------------------------------------------*/ 20 | 21 | int PCS_Utils_assertModuleIsStarted() 22 | { 23 | if (! ut_moduleIsStarted(MODULE_NAME, sizeof(MODULE_NAME) - 1)) { 24 | php_error(E_CORE_ERROR,"Cannot call PCS before it is started. Please use a module dependency"); 25 | return FAILURE; 26 | } 27 | 28 | return SUCCESS; 29 | } 30 | 31 | /*===============================================================*/ 32 | 33 | static zend_always_inline int MINIT_PCS_Utils(TSRMLS_D) 34 | { 35 | return SUCCESS; 36 | } 37 | 38 | /*---------------------------------------------------------------*/ 39 | 40 | static zend_always_inline int MSHUTDOWN_PCS_Utils(TSRMLS_D) 41 | { 42 | return SUCCESS; 43 | } 44 | 45 | /*---------------------------------------------------------------*/ 46 | 47 | static zend_always_inline int RINIT_PCS_Utils(TSRMLS_D) 48 | { 49 | return SUCCESS; 50 | } 51 | /*---------------------------------------------------------------*/ 52 | 53 | static zend_always_inline int RSHUTDOWN_PCS_Utils(TSRMLS_D) 54 | { 55 | return SUCCESS; 56 | } 57 | 58 | /*===============================================================*/ 59 | -------------------------------------------------------------------------------- /src/PCS_Utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PCS extension | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 2015 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt. | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Author: Francois Laupretre | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | #ifndef __PCS_UTILS_H 20 | #define __PCS_UTILS_H 21 | 22 | /*============================================================================*/ 23 | 24 | static int in_startup = 1; 25 | 26 | /*-----------------------------------------------------*/ 27 | 28 | static int PCS_Utils_assertModuleIsStarted(void); 29 | 30 | /*============================================================================*/ 31 | #endif 32 | -------------------------------------------------------------------------------- /tests/autoload_001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | __autoload() is functional 3 | --SKIPIF-- 4 | = 70200) die("skip PHP < 7.2 only"); ?> 5 | --FILE-- 6 | 16 | ===DONE=== 17 | --EXPECTF-- 18 | string(9) "undefined" 19 | ===DONE=== 20 | -------------------------------------------------------------------------------- /tests/autoload_002.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | spl_autoload() is functional 3 | --FILE-- 4 | 14 | ===DONE=== 15 | --EXPECTF-- 16 | string(9) "undefined" 17 | ===DONE=== 18 | -------------------------------------------------------------------------------- /tests/basic_001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Load extension and quit 3 | --FILE-- 4 | ===DONE=== 5 | --EXPECT-- 6 | ===DONE=== 7 | -------------------------------------------------------------------------------- /tests/basic_002.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check existence of Mgr class 3 | --FILE-- 4 | 9 | ===DONE=== 10 | --EXPECT-- 11 | bool(true) 12 | ===DONE=== 13 | -------------------------------------------------------------------------------- /tests/file_info_001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Display information about virtual files (text) 3 | --FILE-- 4 | 7 | ===DONE=== 8 | --EXPECTF-- 9 | -------------------------------------------------- 10 | | Virtual path | Size | L | 11 | |-------------------------------------+------+---| 12 | | internal/parser/ParserInterface.php | %s | - | 13 | | internal/parser/StringParser.php | %s | - | 14 | | internal/tools/Display.php | %s | A | 15 | | internal/tools/embed.php | %s | - | 16 | ===DONE=== 17 | -------------------------------------------------------------------------------- /tests/file_info_002.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Display information about virtual files (html) 3 | --FILE-- 4 | 7 | ===DONE=== 8 | --EXPECTF-- 9 | 10 | 11 | 12 | 13 | 14 | 15 |
Virtual pathSizeLoad
internal/parser/ParserInterface.php%d
-
internal/parser/StringParser.php%d
-
internal/tools/Display.php%d
A
internal/tools/embed.php%d
-
16 | ===DONE=== 17 | -------------------------------------------------------------------------------- /tests/register_001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Register/unregister/list functions 3 | --FILE-- 4 | 29 | ===DONE=== 30 | --EXPECTF-- 31 | 1----- 32 | bool(false) 33 | 2----- 34 | bool(true) 35 | 3----- 36 | array(1) { 37 | [0]=> 38 | string(3) "foo" 39 | } 40 | 4----- 41 | bool(true) 42 | 5----- 43 | array(0) { 44 | } 45 | ===DONE=== 46 | -------------------------------------------------------------------------------- /tests/stream_001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check the PCS stream wrapper 3 | --FILE-- 4 | 60 | ===DONE=== 61 | --EXPECT-- 62 | string(3) "dir" 63 | string(4) "file" 64 | bool(true) 65 | bool(true) 66 | bool(false) 67 | bool(true) 68 | bool(true) 69 | bool(false) 70 | bool(false) 71 | bool(false) 72 | array(2) { 73 | [0]=> 74 | string(19) "ParserInterface.php" 75 | [1]=> 76 | string(16) "StringParser.php" 77 | } 78 | --- fopen/fread/fseek 79 | bool(true) 80 | --- read part1 81 | --- fseek(-5) 82 | int(0) 83 | bool(false) 84 | --- fseek(-50) 85 | int(0) 86 | bool(false) 87 | --- seek to end 88 | int(0) 89 | bool(false) 90 | --- check ftell 91 | bool(true) 92 | int(0) 93 | bool(false) 94 | --- read part2 95 | int(0) 96 | bool(true) 97 | --- check concat 98 | bool(true) 99 | --- fclose 100 | bool(true) 101 | ===DONE=== 102 | -------------------------------------------------------------------------------- /tests/symbol_info_001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Display information about symbols (text) 3 | --FILE-- 4 | 7 | ===DONE=== 8 | --EXPECTF-- 9 | -------------------------------------------------------- 10 | | Type | Name | Virtual path | L | 11 | |-------+-------------+----------------------------+---| 12 | | Class | PCS\Display | internal/tools/Display.php | A | 13 | ===DONE=== 14 | -------------------------------------------------------------------------------- /tests/symbol_info_002.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Display information about symbols (html) 3 | --FILE-- 4 | 7 | ===DONE=== 8 | --EXPECTF-- 9 | 10 | 11 | 12 |
TypeNameVirtual pathLoad
Class
PCS\Displayinternal/tools/Display.php
A
13 | ===DONE=== 14 | --------------------------------------------------------------------------------