├── .github ├── FUNDING.yml ├── actions │ └── install-linux │ │ └── action.yml └── workflows │ └── main.yml ├── .gitignore ├── CREDITS ├── LICENSE ├── README.md ├── build_scripts ├── README.md ├── php-fb-build-all.bat ├── php-fb-build-linux.sh ├── php-fb-build.bat ├── php-fb-config.bat ├── php-fb-sdk-build.bat └── php-fb-sdk-init.bat ├── config.m4 ├── config.w32 ├── ibase_blobs.c ├── ibase_events.c ├── ibase_query.c ├── ibase_service.c ├── interbase.c ├── pdo_firebird_utils.cpp ├── pdo_firebird_utils.h ├── php_ibase_includes.h ├── php_ibase_udf.c ├── php_interbase.h └── tests ├── 002.phpt ├── 003.phpt ├── 004.phpt ├── 005.phpt ├── 006.phpt ├── 007.phpt ├── 008.phpt ├── bug45373.phpt ├── bug45575.phpt ├── bug46247_001.phpt ├── bug46247_002.phpt ├── bug46247_003.phpt ├── bug46247_004.phpt ├── bug46543.phpt ├── config.inc ├── datatype_char_utf8.phpt ├── datatype_int128.phpt ├── functions.inc ├── ibase_affected_rows_001.phpt ├── ibase_close_001.phpt ├── ibase_close_002.phpt ├── ibase_close_003.phpt ├── ibase_commit_001.phpt ├── ibase_commit_ret_001.phpt ├── ibase_drop_db_001.phpt ├── ibase_drop_db_002.phpt ├── ibase_drop_db_003.phpt ├── ibase_drop_db_004.phpt ├── ibase_errmsg_001.phpt ├── ibase_free_query_001.phpt ├── ibase_free_query_002.phpt ├── ibase_num_fields_001.phpt ├── ibase_num_fields_002.phpt ├── ibase_num_fields_003.phpt ├── ibase_num_fields_004.phpt ├── ibase_num_params_001.phpt ├── ibase_num_params_002.phpt ├── ibase_num_params_003.phpt ├── ibase_num_params_004.phpt ├── ibase_param_info_001.phpt ├── ibase_param_info_002.phpt ├── ibase_param_info_003.phpt ├── ibase_rollback_001.phpt ├── ibase_rollback_002.phpt ├── ibase_rollback_ret_001.phpt ├── ibase_trans_001.phpt ├── ibase_trans_002.phpt ├── ibase_trans_003.phpt ├── interbase.inc ├── skipif-php7-or-older.inc ├── skipif-php8-or-newer.inc └── skipif.inc /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 12 | polar: # Replace with a single Polar username 13 | buy_me_a_coffee: # Replace with a single Buy Me a Coffee username 14 | thanks_dev: # Replace with a single thanks.dev username 15 | custom: https://firebirdsql.org/en/donate/ 16 | -------------------------------------------------------------------------------- /.github/actions/install-linux/action.yml: -------------------------------------------------------------------------------- 1 | name: Install 2 | runs: 3 | using: composite 4 | steps: 5 | - shell: bash 6 | run: | 7 | export DEBIAN_FRONTEND="noninteractive" 8 | sudo apt-get update 9 | sudo apt-get -y -q install firebird-dev firebird3.0 firebird3.0-common firebird3.0-server 10 | FB_ORIGINAL_PASS=`sudo cat /etc/firebird/3.0/SYSDBA.password | grep ISC_PASSWORD | sed -e 's/ISC_PASSWORD="\([^"]*\)".*/\1/'` 11 | gsec -user SYSDBA -password ${FB_ORIGINAL_PASS} -modify sysdba -pw masterkey 12 | sudo service firebird3.0 restart 13 | sudo apt-get -y install pkg-config build-essential autoconf bison re2c libxml2-dev libsqlite3-dev 14 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | pull_request: 4 | schedule: 5 | - cron: '0 0 * * *' 6 | 7 | jobs: 8 | linux: 9 | runs-on: ubuntu-latest 10 | continue-on-error: false 11 | strategy: 12 | fail-fast: false 13 | matrix: 14 | php: ['7.4', '8.0', '8.1', '8.2'] 15 | steps: 16 | - name: Checkout php-src 17 | uses: actions/checkout@v3 18 | with: 19 | repository: 'php/php-src' 20 | ref: 'PHP-${{ matrix.php }}' 21 | - name: Checkout php-firebird 22 | uses: actions/checkout@v3 23 | with: 24 | path: 'ext/php-firebird' 25 | - name: Install dependencies 26 | uses: ./ext/php-firebird/.github/actions/install-linux 27 | - name: Build 28 | run: | 29 | ./buildconf --force 30 | ./configure --disable-all --with-interbase 31 | make -j$(/usr/bin/nproc) 32 | - name: Test 33 | run: sudo make test TESTS='ext/php-firebird --show-diff' 34 | linux-debug: 35 | runs-on: ubuntu-latest 36 | continue-on-error: false 37 | strategy: 38 | fail-fast: false 39 | matrix: 40 | php: ['7.4', '8.0', '8.1', '8.2'] 41 | steps: 42 | - name: Checkout php-src 43 | uses: actions/checkout@v3 44 | with: 45 | repository: 'php/php-src' 46 | ref: 'PHP-${{ matrix.php }}' 47 | - name: Checkout php-firebird 48 | uses: actions/checkout@v3 49 | with: 50 | path: 'ext/php-firebird' 51 | - name: Install dependencies 52 | uses: ./ext/php-firebird/.github/actions/install-linux 53 | - name: Build 54 | run: | 55 | ./buildconf --force 56 | ./configure --disable-all --with-interbase --enable-debug 57 | make -j$(/usr/bin/nproc) 58 | - name: Test 59 | run: sudo make test TESTS='ext/php-firebird --show-diff' 60 | 61 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | .deps 3 | .libs 4 | .php-version 5 | .rbenv-version 6 | acinclude.m4 7 | aclocal.m4 8 | autom4te.cache 9 | build 10 | config.guess 11 | config.h 12 | config.h.in 13 | config.log 14 | config.nice 15 | config.status 16 | config.sub 17 | configure 18 | configure.in 19 | configure.ac 20 | extras 21 | include 22 | install-sh 23 | libtool 24 | ltmain.sh 25 | ltmain.sh.backup 26 | Makefile 27 | Makefile.fragments 28 | Makefile.global 29 | Makefile.objects 30 | missing 31 | mkinstalldirs 32 | modules 33 | run-tests.php 34 | tmp-php.ini 35 | yaml.loT 36 | 37 | # General Ignores 38 | *~ 39 | .#* 40 | *. 41 | *.slo 42 | *.mk 43 | *.mem 44 | *.gcda 45 | *.gcno 46 | *.la 47 | *.lo 48 | *.o 49 | *.a 50 | *.ncb 51 | *.opt 52 | *.plg 53 | *swp 54 | *.patch 55 | *.tgz 56 | *.tar.gz 57 | *.tar.bz2 58 | .FBCIndex 59 | .FBCLockFolder 60 | core 61 | *.dep 62 | 63 | # Test specific Ignores 64 | tests/*.diff 65 | tests/*.exp 66 | tests/*.log 67 | tests/*.out 68 | tests/*.php 69 | tests/*.sh 70 | 71 | # coverage 72 | /coverage.info 73 | /reports 74 | -------------------------------------------------------------------------------- /CREDITS: -------------------------------------------------------------------------------- 1 | InterBase 2 | Jouni Ahto, Andrew Avdeev, Ard Biesheuvel 3 | 4 | Firebird 5 | You can find the contributors list at https://github.com/FirebirdSQL/php-firebird/graphs/contributors. 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------- 2 | The PHP License, version 3.01 3 | Copyright (c) 1999 - 2019 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PHP Firebird extension 2 | 3 | ## Using the driver on Windows 4 | In order for this extension to work, there are DLL files that must be available to the Windows system PATH. For information on how to do this, see the FAQ entitled "How do I add my PHP directory to the PATH on Windows" (https://www.php.net/manual/en/faq.installation.php#faq.installation.addtopath). Although copying DLL files from the PHP folder into the Windows system directory also works (because the system directory is by default in the system's PATH), this is not recommended. This extension requires the following files to be in the PATH: fbclient.dll,gds32.dll 5 | 6 | If you installed the Firebird/InterBase database server on the same machine PHP is running on, you will have this DLL already and fbclient.dll, gds32.dll (gds32.dll is generated from the installer for legacy applications) will already be in the PATH. 7 | 8 | ## Building the driver 9 | 10 | ### Build the driver on Linux 11 | First of all, we have to meet some requirements. This means we need to install the `phpize` command. The `phpize` command is used to prepare the build environment for a PHP extension. 12 | Install the `phpize` command. This is usually done by installing the `php7-devel` or `php8-devel` package using the system's package manager. Also install the fbclient library and developer packages. 13 | 14 | For OpenSuse 15.1 and PHP 7 use 15 | ``` 16 | $ zypper in php7-devel libfbclient2 libfbclient-devel 17 | ``` 18 | 19 | The command in Linux Mint 20 / Ubuntu is 20 | ``` 21 | sudo apt-get install php-dev firebird-dev firebird3.0 firebird3.0-common firebird3.0-server 22 | ``` 23 | 24 | Now make sure you provide the fbclient.so and the header files (ibase.h). These are needed to compile. You can specify the include path for the ibase.h file with CPPFLAGS as you can see in the following listing. 25 | ``` 26 | $ git clone https://github.com/FirebirdSQL/php-firebird.git 27 | $ cd php-firebird 28 | $ phpize 29 | $ CPPFLAGS=-I/usr/include/firebird ./configure 30 | $ make 31 | ``` 32 | 33 | Note: If you use different PHP versions in parallel don't forget to make the correct settings. Linux Mint 20 / Ubuntu uses this syntax: 34 | ``` 35 | $ git clone https://github.com/FirebirdSQL/php-firebird.git 36 | $ cd php-firebird 37 | $ phpize7.4 38 | $ CPPFLAGS=-I/usr/include/firebird ./configure --with-php-config=/usr/bin/php-config7.4 39 | $ make 40 | ``` 41 | 42 | If the configure process passes you will get following message: 43 | ``` 44 | $ Build complete. 45 | $ Don't forget to run 'make test'. 46 | ``` 47 | You can find the `interbase.so` file in directory `php-firebird/modules`. Copy the file to your php extension dir and restart your webserver. 48 | 49 | #### Clean up your working directory 50 | After you've created the binary data, many temporary files will be created in your working directory. These can be removed with the command `phpize --clean`. Then you have a tidy directory again. 51 | 52 | ### Build the driver on Windows 53 | First of all, we have to meet some requirements. This means we need to install the Git for Windows and Visual Studio 2017 with following components: 54 | Visual C++ 2017 (vc15) or Visual C++ 2019 (vs16) must be installed prior SDK usage. Required components 55 | - C++ dev 56 | - Windows SDK 57 | - .NET dev 58 | 59 | Also make sure you are using a 64-bit build host with Windows 7 or later. 60 | Of course we need some Firebird related stuff. The easiest way is to install the related Firebird version on your build host including the development files. 61 | 62 | To start the build process open a command line. We assume that the build is done in the directory `c:\php-sdk`. So make sure you have the permission to create that folder on Drive C:. 63 | ``` 64 | git clone https://github.com/Microsoft/php-sdk-binary-tools.git c:\php-sdk 65 | cd c:\php-sdk 66 | git checkout php-sdk-2.2.0 67 | ``` 68 | With the above we downloaded the PHP SDK and entered our working directory. 69 | 70 | Next we will prepare our build environment. 71 | For Win32 do: 72 | ``` 73 | phpsdk-vc15-x86.bat 74 | ``` 75 | Use following command for Win64: 76 | ``` 77 | phpsdk-vc15-x64.bat 78 | ``` 79 | If you use VS 2019, replace vc15 by vs16. 80 | 81 | Now let's create the build structure, download the PHP sources and checkout the desired development branch: 82 | ``` 83 | phpsdk_buildtree phpmaster 84 | git clone https://github.com/php/php-src.git && cd php-src && git checkout PHP-7.4.0 85 | ``` 86 | 87 | Since we have our PHP sources now, we're on to get the depending libraries. 88 | ``` 89 | phpsdk_deps --update --branch 7.4 90 | ``` 91 | 92 | In the next step we will download our Firebird extension sources. 93 | ``` 94 | mkdir ..\pecl 95 | git clone https://github.com/FirebirdSQL/php-firebird.git ..\pecl\interbase 96 | ``` 97 | 98 | If everything is ok, we can now compile our PHP extension. Please specify the the correct path to your Firebird installation. 99 | 100 | #### Build TS extension 101 | Usually you will build thread safe extensions. 102 | For Win32 thread safe (TS) do: 103 | ``` 104 | buildconf --force && configure --disable-all --enable-cli --with-interbase="shared,C:\Program Files (x86)\Firebird\3_0" && nmake 105 | ``` 106 | For Win64thread safe (TS) do: 107 | ``` 108 | buildconf --force && configure --disable-all --enable-cli --with-interbase="shared,C:\Program Files\Firebird\3_0\lib" && nmake 109 | ``` 110 | After the compilation you can find your extension called `php_interbase.dll` e.g. in `C:\php-sdk\phpmaster\vc15\x64\php-src\x64\Release_TS\php_interbase.dll` 111 | Replace x64 with x86 for Win32. 112 | 113 | #### Build NTS extension 114 | For Win32 non-thread safe (NTS) run: 115 | ``` 116 | buildconf --force && configure --disable-zts --disable-all --enable-cli --with-interbase="shared,C:\Program Files (x86)\Firebird\3_0" && nmake 117 | ``` 118 | For Win64 non-thread safe (NTS) run: 119 | ``` 120 | buildconf --force && configure --disable-zts --disable-all --enable-cli --with-interbase="shared,C:\Program Files\Firebird\3_0\lib" && nmake 121 | ``` 122 | After the compilation you can find your extension called `php_interbase.dll` e.g. in `C:\php-sdk\phpmaster\vc15\x86\php-src\Release` 123 | Replace x86 with x64 for Win64. 124 | 125 | #### Clean up your working directory 126 | After you've created the binary data, many temporary files will be created in your working directory. These can be removed with the command `nmake clean`. Then you have a tidy directory again. 127 | 128 | 129 | 130 | 131 | -------------------------------------------------------------------------------- /build_scripts/README.md: -------------------------------------------------------------------------------- 1 | # Scripts building php-firebird extension on Windows 2 | 3 | ## How it works 4 | 5 | These scripts will clone or pull corresponding PHP version(s) from the PHP source repo and build 4 .dll files per PHP version: x86, x64 and ts and non-ts for each architecture. 6 | 7 | Do not run scripts with ``-sdk-`` in their files names directly. These are called from php-sdk environment. 8 | 9 | Make sure you got ~20GB free disk space to build for all PHP versions. 10 | 11 | ## Set up 12 | 13 | Make sure ``git`` is in you PATH 14 | 15 | 1. Set up Microsoft Visual Studio vc15, vs16 and vs17 (for PHP8.4+). 16 | 2. Set up Firebird 32-bit and 64-bit installations or libraries. 17 | 3. Set up PHP-SDK according to https://wiki.php.net/internals/windows/stepbystepbuild_sdk_2 18 | 4. Clone php-firebird extension source somewhere. 19 | 4. Copy these build scripts to C:\php-sdk\ 20 | 5. Adjust php-fb-config.bat. 21 | 22 | ``Note: PFB_SOURCE_DIR should point one level up. For example 23 | PFB_SOURCE_DIR=D:\php-firebird\ then your source should reside in D:\php-firebird\php-firebird\ 24 | `` 25 | 6. Run ``php-fb-build-all.bat`` to build for all PHP versions or run ``php-fb-build.bat 7.4 vc15`` to build for particular version. 26 | -------------------------------------------------------------------------------- /build_scripts/php-fb-build-all.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | call php-fb-build.bat 7.3 vc15 || exit /B %ERRORLEVEL% 4 | call php-fb-build.bat 7.4 vc15 || exit /B %ERRORLEVEL% 5 | call php-fb-build.bat 8.0 vs16 || exit /B %ERRORLEVEL% 6 | call php-fb-build.bat 8.1 vs16 || exit /B %ERRORLEVEL% 7 | call php-fb-build.bat 8.2 vs16 || exit /B %ERRORLEVEL% 8 | call php-fb-build.bat 8.3 vs16 || exit /B %ERRORLEVEL% 9 | call php-fb-build.bat 8.4 vs17 || exit /B %ERRORLEVEL% 10 | call php-fb-build.bat master vs17 || exit /B %ERRORLEVEL% 11 | -------------------------------------------------------------------------------- /build_scripts/php-fb-build-linux.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Configuration 4 | FIREBIRD_INCLUDE_DIR="/opt/firebird/include" 5 | INSTALL_DIR="../ext" 6 | REPO_URL="https://github.com/FirebirdSQL/php-firebird.git" 7 | DRIVER_VERSION="5.0.2" 8 | BRANCH_OR_COMMIT="master" # Set to a specific tag or commit if needed 9 | PHP_VERSIONS=("7.4" "8.0" "8.1" "8.2" "8.3" "8.4") # Adjust as needed 10 | BUILD_DIR="php-firebird-build" 11 | 12 | set -e 13 | 14 | mkdir -p "$INSTALL_DIR" 15 | rm -rf "$BUILD_DIR" 16 | echo "Cloning repository from $REPO_URL (branch: $BRANCH_OR_COMMIT)..." 17 | git clone --depth 1 --branch "$BRANCH_OR_COMMIT" "$REPO_URL" "$BUILD_DIR" 18 | 19 | for VERSION in "${PHP_VERSIONS[@]}"; do 20 | echo "==> Building for PHP $VERSION" 21 | 22 | PHP_BIN="/usr/bin/php$VERSION" 23 | PHPIZE="/usr/bin/phpize$VERSION" 24 | PHP_CONFIG="/usr/bin/php-config$VERSION" 25 | 26 | if [[ ! -x "$PHP_BIN" || ! -x "$PHPIZE" || ! -x "$PHP_CONFIG" ]]; then 27 | echo "--> Installing missing PHP $VERSION packages..." 28 | sudo apt-get install -y "php$VERSION-dev" "php$VERSION-cli" "php$VERSION-common" 29 | fi 30 | 31 | cd "$BUILD_DIR" 32 | 33 | echo "--> Cleaning previous build (if any)..." 34 | make clean || true 35 | echo "--> Running phpize..." 36 | "$PHPIZE" 37 | echo "--> Configuring build..." 38 | CPPFLAGS="-I$FIREBIRD_INCLUDE_DIR" ./configure --with-php-config="$PHP_CONFIG" 39 | echo "--> Compiling..." 40 | make -j"$(nproc)" 41 | 42 | PHP_FULL_VERSION=$("$PHP_BIN" -r 'echo PHP_VERSION;') 43 | ARCH=$(uname -m) 44 | OS=$(uname -s | tr '[:upper:]' '[:lower:]') 45 | 46 | OUTPUT_FILE="php_${PHP_FULL_VERSION}-interbase-${DRIVER_VERSION}-${OS}-${ARCH}.so" 47 | mkdir -p "$INSTALL_DIR" 48 | echo "--> Copying output to $INSTALL_DIR/$OUTPUT_FILE" 49 | cp modules/interbase.so "$INSTALL_DIR/$OUTPUT_FILE" 50 | 51 | echo "Build complete for PHP $VERSION: $OUTPUT_FILE" 52 | cd .. 53 | done 54 | 55 | echo "All builds completed. Files are located in: $INSTALL_DIR" 56 | 57 | -------------------------------------------------------------------------------- /build_scripts/php-fb-build.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | @REM config ====================================================================================== 4 | call php-fb-config.bat 5 | 6 | goto :MAIN 7 | 8 | @REM log ========================================================================================= 9 | @REM log 10 | @REM example> call :log "" 11 | :log 12 | set msg=%~1 13 | echo --------------------------------------------------------------------- 14 | echo %msg% 15 | echo --------------------------------------------------------------------- 16 | exit /B 17 | 18 | :usage 19 | call :log "Usage: %~nx0 php_vers cpp_vers" 20 | exit /B 21 | 22 | :MAIN 23 | set pfb_php_vers=%1 24 | set pfb_cpp_vers=%2 25 | 26 | if [%pfb_php_vers%] == [] ( 27 | call :usage 28 | echo pfb_php_vers varible not set 29 | exit 1 30 | ) 31 | 32 | if [%pfb_cpp_vers%] == [] ( 33 | call :usage 34 | echo pfb_cpp_vers varible not set 35 | exit 1 36 | ) 37 | 38 | set pfb_build_root=php%pfb_php_vers%\%pfb_cpp_vers%\ 39 | 40 | (for %%a in (x86 x64) do ( 41 | @REM check out or pull PHP version of interest 42 | if exist %pfb_build_root%\%%a\php-src\.git\ ( 43 | call :log "Checking out PHP-%pfb_php_vers% %%a" 44 | git -C %pfb_build_root%\%%a\php-src pull || goto :error 45 | ) else ( 46 | call :log "Cloning PHP-%pfb_php_vers% %%a" 47 | call phpsdk-%pfb_cpp_vers%-%%a.bat -t php-fb-sdk-init.bat || goto :error 48 | ) 49 | 50 | if %%a EQU x86 ( set pfb_x86=1 ) else ( set pfb_x86=0 ) 51 | 52 | (for %%n in (0 1) do ( 53 | set pfb_nts=%%n 54 | call phpsdk-%pfb_cpp_vers%-%%a.bat -t php-fb-sdk-build.bat || goto :error 55 | )) 56 | )) 57 | 58 | @REM check if ibase_connect() function exists in newly compiled extension 59 | set check_code="if(!function_exists('ibase_connect'))exit(1);" 60 | 61 | set TPATH=%PATH% 62 | set PATH=%FB64_DIR%;%TPATH% 63 | "%pfb_build_root%x64\php-src\x64\Release_TS\php.exe" -dextension=.\php_interbase.dll -r %check_code% || goto :error 64 | "%pfb_build_root%x64\php-src\x64\Release\php.exe" -dextension=.\php_interbase.dll -r %check_code% || goto :error 65 | set PATH=%FB32_DIR%;%TPATH% 66 | "%pfb_build_root%x86\php-src\Release_TS\php.exe" -dextension=.\php_interbase.dll -r %check_code% || goto :error 67 | "%pfb_build_root%x86\php-src\Release\php.exe" -dextension=.\php_interbase.dll -r %check_code% || goto :error 68 | set PATH=%TPATH% 69 | 70 | call :log "PHP %pfb_php_vers% build OK" 71 | 72 | @REM copy compiled extension to target directory 73 | copy %pfb_build_root%x64\php-src\x64\Release_TS\php_interbase.dll %PFB_OUTPUT_DIR%php_interbase-%PFB_VERS%-%pfb_php_vers%-%pfb_cpp_vers%-x86_64.dll>nul 74 | copy %pfb_build_root%x64\php-src\x64\Release\php_interbase.dll %PFB_OUTPUT_DIR%php_interbase-%PFB_VERS%-%pfb_php_vers%-%pfb_cpp_vers%-nts-x86_64.dll>nul 75 | copy %pfb_build_root%x86\php-src\Release_TS\php_interbase.dll %PFB_OUTPUT_DIR%php_interbase-%PFB_VERS%-%pfb_php_vers%-%pfb_cpp_vers%.dll>nul 76 | copy %pfb_build_root%x86\php-src\Release\php_interbase.dll %PFB_OUTPUT_DIR%php_interbase-%PFB_VERS%-%pfb_php_vers%-%pfb_cpp_vers%-nts.dll>nul 77 | 78 | exit /B 0 79 | 80 | :error 81 | call :log "PHP %pfb_php_vers% build FAILED" 82 | 83 | exit /B 1 84 | -------------------------------------------------------------------------------- /build_scripts/php-fb-config.bat: -------------------------------------------------------------------------------- 1 | @REM 2 | @REM git command must be in PATH 3 | @REM 4 | 5 | @REM php-firebird source directory 6 | set PFB_SOURCE_DIR=D:\php-firebird\ 7 | 8 | for /f %%i in ('git -C %PFB_SOURCE_DIR%\php-firebird\ rev-parse --short HEAD') do set GIT_HASH=%%i 9 | 10 | @REM sets php-firebird version part in extension file, for example, php_interbase-<<3.0.1-ba8e63b>>-7.3-vc15.dll 11 | set PFB_VERS=3.0.1-%GIT_HASH% 12 | 13 | @REM Directory where all compiled files will be copied 14 | set PFB_OUTPUT_DIR=D:\php-firebird\releases\ 15 | 16 | @REM FB 32-bit and 64-bit libraries 17 | set FB32_DIR=C:\Program Files\Firebird\Firebird_5_0-x86 18 | set FB64_DIR=C:\Program Files\Firebird\Firebird_5_0 19 | -------------------------------------------------------------------------------- /build_scripts/php-fb-sdk-build.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | @REM 3 | @REM Must be called under phpsdk--.bat 4 | @REM 5 | @REM Calling script should set variables: 6 | @REM [pfb_nts] [pfb_x86] 7 | @REM 8 | @REM set pfb_php_vers=7.4 9 | @REM set pfb_nts=1 if nts expected, 0 if ts 10 | @REM set pfb_x86=1 if linking to x86 fbclient, o if x64 11 | @REM 12 | @REM all set in php-fb-config.bat 13 | @REM 14 | 15 | goto :MAIN 16 | 17 | @REM log ========================================================================================= 18 | @REM log 19 | @REM example> call :log "" 20 | :log 21 | set msg=%~1 22 | echo --------------------------------------------------------------------- 23 | echo %msg% 24 | echo --------------------------------------------------------------------- 25 | exit /B 26 | 27 | :MAIN 28 | if [%pfb_php_vers%] == [] ( 29 | echo pfb_php_vers varible not set 30 | exit 1 31 | ) 32 | 33 | set build_msg=Building PHP-%pfb_php_vers% 34 | 35 | if "%pfb_nts%" gtr "0" ( 36 | set build_msg=%build_msg% non-TS 37 | set extra_args=--disable-zts 38 | ) else ( 39 | set build_msg=%build_msg% TS 40 | set extra_args= 41 | ) 42 | 43 | if "%pfb_x86%" gtr "0" ( 44 | set with_interbase="shared,%FB32_DIR%" 45 | set build_msg=%build_msg% x86 46 | ) else ( 47 | set with_interbase="shared,%FB64_DIR%" 48 | set build_msg=%build_msg% x86_64 49 | ) 50 | 51 | call :log "%build_msg%" 52 | 53 | call phpsdk_buildtree php%pfb_php_vers% 54 | cd /D php-src 55 | call buildconf.bat --force --add-modules-dir=%PFB_SOURCE_DIR% 56 | call configure.bat --disable-all --enable-cli %extra_args% --with-interbase=%with_interbase% 57 | nmake 58 | -------------------------------------------------------------------------------- /build_scripts/php-fb-sdk-init.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | @REM 3 | @REM Must be called under phpsdk--.bat 4 | @REM 5 | @REM Calling script should set variables: 6 | @REM 7 | @REM set pfb_php_vers=7.4 8 | 9 | if [%pfb_php_vers%] == [] ( 10 | echo pfb_php_vers varible not set 11 | exit 1 12 | ) 13 | 14 | @REM Handle current master branch 15 | if "%pfb_php_vers%" == "master" ( 16 | set pfb_git_args= 17 | ) else ( 18 | set pfb_git_args=--branch PHP-%pfb_php_vers% 19 | ) 20 | 21 | call phpsdk_buildtree php%pfb_php_vers% 22 | git clone --depth 1 %pfb_git_args% https://github.com/php/php-src.git 23 | cd php-src 24 | 25 | @REM Remove built-in extension 26 | if "%pfb_php_vers%" == "7.3" ( 27 | rd /Q /S ext\interbase 28 | ) 29 | 30 | call phpsdk_deps --update 31 | -------------------------------------------------------------------------------- /config.m4: -------------------------------------------------------------------------------- 1 | PHP_ARG_WITH([interbase], 2 | [for Firebird support], 3 | [AS_HELP_STRING([[--with-interbase[=DIR]]], 4 | [Include Firebird support. DIR is the Firebird base install directory 5 | [/opt/firebird]])]) 6 | 7 | if test "$PHP_INTERBASE" != "no"; then 8 | 9 | AC_PATH_PROG(FB_CONFIG, fb_config, no) 10 | 11 | if test -x "$FB_CONFIG" && test "$PHP_INTERBASE" = "yes"; then 12 | AC_MSG_CHECKING(for libfbconfig) 13 | FB_CFLAGS=`$FB_CONFIG --cflags` 14 | FB_LIBDIR=`$FB_CONFIG --libs` 15 | FB_VERSION=`$FB_CONFIG --version` 16 | AC_MSG_RESULT(version $FB_VERSION) 17 | PHP_EVAL_LIBLINE($FB_LIBDIR, INTERBASE_SHARED_LIBADD) 18 | PHP_EVAL_INCLINE($FB_CFLAGS) 19 | 20 | else 21 | if test "$PHP_INTERBASE" = "yes"; then 22 | IBASE_INCDIR=/opt/firebird/include 23 | IBASE_LIBDIR=/opt/firebird/lib 24 | else 25 | IBASE_INCDIR=$PHP_INTERBASE/include 26 | IBASE_LIBDIR=$PHP_INTERBASE/$PHP_LIBDIR 27 | fi 28 | 29 | PHP_CHECK_LIBRARY(fbclient, isc_detach_database, 30 | [ 31 | IBASE_LIBNAME=fbclient 32 | ], [ 33 | PHP_CHECK_LIBRARY(gds, isc_detach_database, 34 | [ 35 | IBASE_LIBNAME=gds 36 | ], [ 37 | PHP_CHECK_LIBRARY(ib_util, isc_detach_database, 38 | [ 39 | IBASE_LIBNAME=ib_util 40 | ], [ 41 | AC_MSG_ERROR([libfbclient, libgds or libib_util not found! Check config.log for more information.]) 42 | ], [ 43 | -L$IBASE_LIBDIR 44 | ]) 45 | ], [ 46 | -L$IBASE_LIBDIR 47 | ]) 48 | ], [ 49 | -L$IBASE_LIBDIR 50 | ]) 51 | 52 | PHP_ADD_LIBRARY_WITH_PATH($IBASE_LIBNAME, $IBASE_LIBDIR, INTERBASE_SHARED_LIBADD) 53 | PHP_ADD_INCLUDE($IBASE_INCDIR) 54 | fi 55 | 56 | AC_DEFINE(HAVE_IBASE,1,[ ]) 57 | PHP_NEW_EXTENSION(interbase, interbase.c ibase_query.c ibase_service.c ibase_events.c ibase_blobs.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1,[cxx]) 58 | PHP_SUBST(INTERBASE_SHARED_LIBADD) 59 | 60 | PHP_REQUIRE_CXX() 61 | PHP_CXX_COMPILE_STDCXX([11], [mandatory], [PHP_INTERBASE_STDCXX]) 62 | 63 | PHP_INTERBASE_CXX_SOURCES="pdo_firebird_utils.cpp" 64 | 65 | AS_VAR_IF([ext_shared], [no], 66 | [PHP_ADD_SOURCES([$ext_dir], 67 | [$PHP_INTERBASE_CXX_SOURCES], 68 | [$PHP_INTERBASE_STDCXX])], 69 | [PHP_ADD_SOURCES_X([$ext_dir], 70 | [$PHP_INTERBASE_CXX_SOURCES], 71 | [$PHP_INTERBASE_STDCXX], 72 | [shared_objects_interbase], 73 | [yes])]) 74 | 75 | fi 76 | -------------------------------------------------------------------------------- /config.w32: -------------------------------------------------------------------------------- 1 | // vim:ft=javascript 2 | 3 | ARG_WITH("interbase", "InterBase support", "no"); 4 | 5 | if (PHP_INTERBASE != "no") { 6 | if ( 7 | CHECK_HEADER_ADD_INCLUDE("ibase.h", "CFLAGS_INTERBASE", PHP_INTERBASE + "\\include") && ( 8 | CHECK_LIB("fbclient_ms.lib", "interbase", PHP_INTERBASE + "\\lib") || 9 | CHECK_LIB("gds32_ms.lib", "interbase", PHP_INTERBASE + "\\lib") 10 | ) 11 | ) { 12 | EXTENSION("interbase", "interbase.c ibase_query.c ibase_service.c ibase_events.c ibase_blobs.c pdo_firebird_utils.cpp", PHP_INTERBASE_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); 13 | AC_DEFINE('HAVE_IBASE', 1, 'Have interbase library'); 14 | } else { 15 | WARNING("interbase not enabled; libraries and headers not found"); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /ibase_blobs.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 7, 8 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 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 | | Authors: Jouni Ahto | 16 | | Andrew Avdeev | 17 | | Ard Biesheuvel | 18 | | Martin Koeditz | 19 | | others | 20 | +----------------------------------------------------------------------+ 21 | | You'll find history on Github | 22 | | https://github.com/FirebirdSQL/php-firebird/commits/master | 23 | +----------------------------------------------------------------------+ 24 | */ 25 | 26 | #ifdef HAVE_CONFIG_H 27 | #include "config.h" 28 | #endif 29 | 30 | #include "php.h" 31 | 32 | #if HAVE_IBASE 33 | 34 | #include "php_interbase.h" 35 | #include "php_ibase_includes.h" 36 | 37 | #define BLOB_CLOSE 1 38 | #define BLOB_CANCEL 2 39 | 40 | #define PARSE_PARAMETERS \ 41 | switch (ZEND_NUM_ARGS()) { \ 42 | default: \ 43 | WRONG_PARAM_COUNT; \ 44 | case 1: \ 45 | if (FAILURE == zend_parse_parameters(1, "s", &blob_id, &blob_id_len)) { \ 46 | RETURN_FALSE; \ 47 | } \ 48 | break; \ 49 | case 2: \ 50 | if (FAILURE == zend_parse_parameters(2, "rs", &link, &blob_id, &blob_id_len)) { \ 51 | RETURN_FALSE; \ 52 | } \ 53 | break; \ 54 | } \ 55 | 56 | static int le_blob; 57 | 58 | static void _php_ibase_free_blob(zend_resource *rsrc) /* {{{ */ 59 | { 60 | ibase_blob *ib_blob = (ibase_blob *)rsrc->ptr; 61 | 62 | if (ib_blob->bl_handle != 0) { /* blob open*/ 63 | if (isc_cancel_blob(IB_STATUS, &ib_blob->bl_handle)) { 64 | _php_ibase_module_error("You can lose data. Close any blob after reading from or " 65 | "writing to it. Use ibase_blob_close() before calling ibase_close()"); 66 | } 67 | } 68 | efree(ib_blob); 69 | } 70 | /* }}} */ 71 | 72 | void php_ibase_blobs_minit(INIT_FUNC_ARGS) /* {{{ */ 73 | { 74 | le_blob = zend_register_list_destructors_ex(_php_ibase_free_blob, NULL, 75 | "interbase blob", module_number); 76 | } 77 | /* }}} */ 78 | 79 | int _php_ibase_string_to_quad(char const *id, ISC_QUAD *qd) /* {{{ */ 80 | { 81 | /* shortcut for most common case */ 82 | if (sizeof(ISC_QUAD) == sizeof(ISC_UINT64)) { 83 | return sscanf(id, BLOB_ID_MASK, (ISC_UINT64 *) qd); 84 | } else { 85 | ISC_UINT64 res; 86 | if (sscanf(id, BLOB_ID_MASK, &res)) { 87 | qd->gds_quad_high = (ISC_LONG) (res >> 0x20); 88 | qd->gds_quad_low = (ISC_LONG) (res & 0xFFFFFFFF); 89 | return 1; 90 | } 91 | return 0; 92 | } 93 | } 94 | /* }}} */ 95 | 96 | zend_string *_php_ibase_quad_to_string(ISC_QUAD const qd) /* {{{ */ 97 | { 98 | /* shortcut for most common case */ 99 | if (sizeof(ISC_QUAD) == sizeof(ISC_UINT64)) { 100 | return strpprintf(BLOB_ID_LEN+1, "0x%0*" LL_MASK "x", 16, *(ISC_UINT64*)(void *) &qd); 101 | } else { 102 | ISC_UINT64 res = ((ISC_UINT64) qd.gds_quad_high << 0x20) | qd.gds_quad_low; 103 | return strpprintf(BLOB_ID_LEN+1, "0x%0*" LL_MASK "x", 16, res); 104 | } 105 | } 106 | /* }}} */ 107 | 108 | typedef struct { /* {{{ */ 109 | ISC_LONG max_segment; /* Length of longest segment */ 110 | ISC_LONG num_segments; /* Total number of segments */ 111 | ISC_LONG total_length; /* Total length of blob */ 112 | int bl_stream; /* blob is stream ? */ 113 | /* }}} */ 114 | } IBASE_BLOBINFO; 115 | 116 | int _php_ibase_blob_get(zval *return_value, ibase_blob *ib_blob, zend_ulong max_len) /* {{{ */ 117 | { 118 | if (ib_blob->bl_qd.gds_quad_high || ib_blob->bl_qd.gds_quad_low) { /*not null ?*/ 119 | 120 | ISC_STATUS stat; 121 | zend_string *bl_data; 122 | zend_ulong cur_len; 123 | unsigned short seg_len; 124 | 125 | bl_data = zend_string_safe_alloc(1, max_len, 0, 0); 126 | 127 | for (cur_len = stat = 0; (stat == 0 || stat == isc_segment) && cur_len < max_len; cur_len += seg_len) { 128 | 129 | unsigned short chunk_size = (max_len-cur_len) > USHRT_MAX ? USHRT_MAX 130 | : (unsigned short)(max_len-cur_len); 131 | 132 | stat = isc_get_segment(IB_STATUS, &ib_blob->bl_handle, &seg_len, chunk_size, &ZSTR_VAL(bl_data)[cur_len]); 133 | } 134 | 135 | if (IB_STATUS[0] == 1 && (stat != 0 && stat != isc_segstr_eof && stat != isc_segment)) { 136 | zend_string_free(bl_data); 137 | _php_ibase_error(); 138 | return FAILURE; 139 | } 140 | ZSTR_VAL(bl_data)[cur_len] = '\0'; 141 | ZSTR_LEN(bl_data) = cur_len; 142 | RETVAL_NEW_STR(bl_data); 143 | } else { /* null blob */ 144 | RETVAL_EMPTY_STRING(); /* empty string */ 145 | } 146 | return SUCCESS; 147 | } 148 | /* }}} */ 149 | 150 | int _php_ibase_blob_add(zval *string_arg, ibase_blob *ib_blob) /* {{{ */ 151 | { 152 | zend_ulong put_cnt = 0, rem_cnt; 153 | unsigned short chunk_size; 154 | 155 | convert_to_string_ex(string_arg); 156 | 157 | for (rem_cnt = Z_STRLEN_P(string_arg); rem_cnt > 0; rem_cnt -= chunk_size) { 158 | 159 | chunk_size = rem_cnt > USHRT_MAX ? USHRT_MAX : (unsigned short)rem_cnt; 160 | 161 | if (isc_put_segment(IB_STATUS, &ib_blob->bl_handle, chunk_size, &Z_STRVAL_P(string_arg)[put_cnt] )) { 162 | _php_ibase_error(); 163 | return FAILURE; 164 | } 165 | put_cnt += chunk_size; 166 | } 167 | return SUCCESS; 168 | } 169 | /* }}} */ 170 | 171 | static int _php_ibase_blob_info(isc_blob_handle bl_handle, IBASE_BLOBINFO *bl_info) /* {{{ */ 172 | { 173 | static char bl_items[] = { 174 | isc_info_blob_num_segments, 175 | isc_info_blob_max_segment, 176 | isc_info_blob_total_length, 177 | isc_info_blob_type 178 | }; 179 | 180 | char bl_inf[sizeof(zend_long)*8], *p; 181 | 182 | bl_info->max_segment = 0; 183 | bl_info->num_segments = 0; 184 | bl_info->total_length = 0; 185 | bl_info->bl_stream = 0; 186 | 187 | if (isc_blob_info(IB_STATUS, &bl_handle, sizeof(bl_items), bl_items, sizeof(bl_inf), bl_inf)) { 188 | _php_ibase_error(); 189 | return FAILURE; 190 | } 191 | 192 | for (p = bl_inf; *p != isc_info_end && p < bl_inf + sizeof(bl_inf);) { 193 | unsigned short item_len; 194 | int item = *p++; 195 | 196 | item_len = (short) isc_vax_integer(p, 2); 197 | p += 2; 198 | switch (item) { 199 | case isc_info_blob_num_segments: 200 | bl_info->num_segments = isc_vax_integer(p, item_len); 201 | break; 202 | case isc_info_blob_max_segment: 203 | bl_info->max_segment = isc_vax_integer(p, item_len); 204 | break; 205 | case isc_info_blob_total_length: 206 | bl_info->total_length = isc_vax_integer(p, item_len); 207 | break; 208 | case isc_info_blob_type: 209 | bl_info->bl_stream = isc_vax_integer(p, item_len); 210 | break; 211 | case isc_info_end: 212 | break; 213 | case isc_info_truncated: 214 | case isc_info_error: /* hmm. don't think so...*/ 215 | _php_ibase_module_error("PHP module internal error"); 216 | return FAILURE; 217 | } /* switch */ 218 | p += item_len; 219 | } /* for */ 220 | return SUCCESS; 221 | } 222 | /* }}} */ 223 | 224 | /* {{{ proto resource ibase_blob_create([resource link_identifier]) 225 | Create blob for adding data */ 226 | PHP_FUNCTION(ibase_blob_create) 227 | { 228 | zval *link = NULL; 229 | ibase_db_link *ib_link; 230 | ibase_trans *trans = NULL; 231 | ibase_blob *ib_blob; 232 | 233 | RESET_ERRMSG; 234 | 235 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "|r", &link)) { 236 | RETURN_FALSE; 237 | } 238 | 239 | PHP_IBASE_LINK_TRANS(link, ib_link, trans); 240 | 241 | ib_blob = (ibase_blob *) emalloc(sizeof(ibase_blob)); 242 | ib_blob->bl_handle = 0; 243 | ib_blob->type = BLOB_INPUT; 244 | 245 | if (isc_create_blob(IB_STATUS, &ib_link->handle, &trans->handle, &ib_blob->bl_handle, &ib_blob->bl_qd)) { 246 | _php_ibase_error(); 247 | efree(ib_blob); 248 | RETURN_FALSE; 249 | } 250 | 251 | RETVAL_RES(zend_register_resource(ib_blob, le_blob)); 252 | Z_TRY_ADDREF_P(return_value); 253 | } 254 | /* }}} */ 255 | 256 | /* {{{ proto resource ibase_blob_open([ resource link_identifier, ] string blob_id) 257 | Open blob for retrieving data parts */ 258 | PHP_FUNCTION(ibase_blob_open) 259 | { 260 | char *blob_id; 261 | size_t blob_id_len; 262 | zval *link = NULL; 263 | ibase_db_link *ib_link; 264 | ibase_trans *trans = NULL; 265 | ibase_blob *ib_blob; 266 | 267 | RESET_ERRMSG; 268 | PARSE_PARAMETERS; 269 | 270 | PHP_IBASE_LINK_TRANS(link, ib_link, trans); 271 | 272 | ib_blob = (ibase_blob *) emalloc(sizeof(ibase_blob)); 273 | ib_blob->bl_handle = 0; 274 | ib_blob->type = BLOB_OUTPUT; 275 | 276 | do { 277 | if (! _php_ibase_string_to_quad(blob_id, &ib_blob->bl_qd)) { 278 | _php_ibase_module_error("String is not a BLOB ID"); 279 | break; 280 | } 281 | 282 | if (isc_open_blob(IB_STATUS, &ib_link->handle, &trans->handle, &ib_blob->bl_handle, 283 | &ib_blob->bl_qd)) { 284 | _php_ibase_error(); 285 | break; 286 | } 287 | 288 | RETVAL_RES(zend_register_resource(ib_blob, le_blob)); 289 | Z_TRY_ADDREF_P(return_value); 290 | return; 291 | 292 | } while (0); 293 | 294 | efree(ib_blob); 295 | RETURN_FALSE; 296 | } 297 | /* }}} */ 298 | 299 | /* {{{ proto bool ibase_blob_add(resource blob_handle, string data) 300 | Add data into created blob */ 301 | PHP_FUNCTION(ibase_blob_add) 302 | { 303 | zval *blob_arg, *string_arg; 304 | ibase_blob *ib_blob; 305 | 306 | RESET_ERRMSG; 307 | 308 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "rz", &blob_arg, &string_arg)) { 309 | return; 310 | } 311 | 312 | ib_blob = (ibase_blob *)zend_fetch_resource_ex(blob_arg, "Interbase blob", le_blob); 313 | 314 | if (ib_blob->type != BLOB_INPUT) { 315 | _php_ibase_module_error("BLOB is not open for input"); 316 | RETURN_FALSE; 317 | } 318 | 319 | if (_php_ibase_blob_add(string_arg, ib_blob) != SUCCESS) { 320 | RETURN_FALSE; 321 | } 322 | } 323 | /* }}} */ 324 | 325 | /* {{{ proto string ibase_blob_get(resource blob_handle, int len) 326 | Get len bytes data from open blob */ 327 | PHP_FUNCTION(ibase_blob_get) 328 | { 329 | zval *blob_arg; 330 | zend_ulong len_arg; 331 | ibase_blob *ib_blob; 332 | 333 | RESET_ERRMSG; 334 | 335 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "rl", &blob_arg, &len_arg)) { 336 | return; 337 | } 338 | 339 | ib_blob = (ibase_blob *)zend_fetch_resource_ex(blob_arg, "Interbase blob", le_blob); 340 | 341 | if (ib_blob->type != BLOB_OUTPUT) { 342 | _php_ibase_module_error("BLOB is not open for output"); 343 | RETURN_FALSE; 344 | } 345 | 346 | if (_php_ibase_blob_get(return_value, ib_blob, len_arg) != SUCCESS) { 347 | RETURN_FALSE; 348 | } 349 | } 350 | /* }}} */ 351 | 352 | static void _php_ibase_blob_end(INTERNAL_FUNCTION_PARAMETERS, int bl_end) /* {{{ */ 353 | { 354 | zval *blob_arg; 355 | ibase_blob *ib_blob; 356 | 357 | RESET_ERRMSG; 358 | 359 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "r", &blob_arg)) { 360 | return; 361 | } 362 | 363 | ib_blob = (ibase_blob *)zend_fetch_resource_ex(blob_arg, "Interbase blob", le_blob); 364 | 365 | if (bl_end == BLOB_CLOSE) { /* return id here */ 366 | 367 | if (ib_blob->bl_qd.gds_quad_high || ib_blob->bl_qd.gds_quad_low) { /*not null ?*/ 368 | if (isc_close_blob(IB_STATUS, &ib_blob->bl_handle)) { 369 | _php_ibase_error(); 370 | RETURN_FALSE; 371 | } 372 | } 373 | ib_blob->bl_handle = 0; 374 | 375 | RETVAL_NEW_STR(_php_ibase_quad_to_string(ib_blob->bl_qd)); 376 | } else { /* discard created blob */ 377 | if (isc_cancel_blob(IB_STATUS, &ib_blob->bl_handle)) { 378 | _php_ibase_error(); 379 | RETURN_FALSE; 380 | } 381 | ib_blob->bl_handle = 0; 382 | RETVAL_TRUE; 383 | } 384 | zend_list_delete(Z_RES_P(blob_arg)); 385 | } 386 | /* }}} */ 387 | 388 | /* {{{ proto string ibase_blob_close(resource blob_handle) 389 | Close blob */ 390 | PHP_FUNCTION(ibase_blob_close) 391 | { 392 | _php_ibase_blob_end(INTERNAL_FUNCTION_PARAM_PASSTHRU, BLOB_CLOSE); 393 | } 394 | /* }}} */ 395 | 396 | /* {{{ proto bool ibase_blob_cancel(resource blob_handle) 397 | Cancel creating blob */ 398 | PHP_FUNCTION(ibase_blob_cancel) 399 | { 400 | _php_ibase_blob_end(INTERNAL_FUNCTION_PARAM_PASSTHRU, BLOB_CANCEL); 401 | } 402 | /* }}} */ 403 | 404 | /* {{{ proto array ibase_blob_info([ resource link_identifier, ] string blob_id) 405 | Return blob length and other useful info */ 406 | PHP_FUNCTION(ibase_blob_info) 407 | { 408 | char *blob_id; 409 | size_t blob_id_len; 410 | zval *link = NULL; 411 | ibase_db_link *ib_link; 412 | ibase_trans *trans = NULL; 413 | ibase_blob ib_blob = { 0, BLOB_INPUT }; 414 | IBASE_BLOBINFO bl_info; 415 | 416 | RESET_ERRMSG; 417 | PARSE_PARAMETERS; 418 | 419 | PHP_IBASE_LINK_TRANS(link, ib_link, trans); 420 | 421 | if (! _php_ibase_string_to_quad(blob_id, &ib_blob.bl_qd)) { 422 | _php_ibase_module_error("Unrecognized BLOB ID"); 423 | RETURN_FALSE; 424 | } 425 | 426 | if (ib_blob.bl_qd.gds_quad_high || ib_blob.bl_qd.gds_quad_low) { /* not null ? */ 427 | if (isc_open_blob(IB_STATUS, &ib_link->handle, &trans->handle, &ib_blob.bl_handle, 428 | &ib_blob.bl_qd)) { 429 | _php_ibase_error(); 430 | RETURN_FALSE; 431 | } 432 | 433 | if (_php_ibase_blob_info(ib_blob.bl_handle, &bl_info)) { 434 | RETURN_FALSE; 435 | } 436 | if (isc_close_blob(IB_STATUS, &ib_blob.bl_handle)) { 437 | _php_ibase_error(); 438 | RETURN_FALSE; 439 | } 440 | } else { /* null blob, all values to zero */ 441 | bl_info.max_segment = 0; 442 | bl_info.num_segments = 0; 443 | bl_info.total_length = 0; 444 | bl_info.bl_stream = 0; 445 | } 446 | 447 | array_init(return_value); 448 | 449 | add_index_long(return_value, 0, bl_info.total_length); 450 | add_assoc_long(return_value, "length", bl_info.total_length); 451 | 452 | add_index_long(return_value, 1, bl_info.num_segments); 453 | add_assoc_long(return_value, "numseg", bl_info.num_segments); 454 | 455 | add_index_long(return_value, 2, bl_info.max_segment); 456 | add_assoc_long(return_value, "maxseg", bl_info.max_segment); 457 | 458 | add_index_bool(return_value, 3, bl_info.bl_stream); 459 | add_assoc_bool(return_value, "stream", bl_info.bl_stream); 460 | 461 | add_index_bool(return_value, 4, (!ib_blob.bl_qd.gds_quad_high && !ib_blob.bl_qd.gds_quad_low)); 462 | add_assoc_bool(return_value, "isnull", (!ib_blob.bl_qd.gds_quad_high && !ib_blob.bl_qd.gds_quad_low)); 463 | } 464 | /* }}} */ 465 | 466 | /* {{{ proto bool ibase_blob_echo([ resource link_identifier, ] string blob_id) 467 | Output blob contents to browser */ 468 | PHP_FUNCTION(ibase_blob_echo) 469 | { 470 | char *blob_id; 471 | size_t blob_id_len; 472 | zval *link = NULL; 473 | ibase_db_link *ib_link; 474 | ibase_trans *trans = NULL; 475 | ibase_blob ib_blob_id = { 0, BLOB_OUTPUT }; 476 | char bl_data[IBASE_BLOB_SEG]; 477 | unsigned short seg_len; 478 | 479 | RESET_ERRMSG; 480 | PARSE_PARAMETERS; 481 | 482 | PHP_IBASE_LINK_TRANS(link, ib_link, trans); 483 | 484 | if (! _php_ibase_string_to_quad(blob_id, &ib_blob_id.bl_qd)) { 485 | _php_ibase_module_error("Unrecognized BLOB ID"); 486 | RETURN_FALSE; 487 | } 488 | 489 | do { 490 | if (isc_open_blob(IB_STATUS, &ib_link->handle, &trans->handle, &ib_blob_id.bl_handle, 491 | &ib_blob_id.bl_qd)) { 492 | break; 493 | } 494 | 495 | while (!isc_get_segment(IB_STATUS, &ib_blob_id.bl_handle, &seg_len, sizeof(bl_data), bl_data) 496 | || IB_STATUS[1] == isc_segment) { 497 | PHPWRITE(bl_data, seg_len); 498 | } 499 | 500 | if (IB_STATUS[0] && (IB_STATUS[1] != isc_segstr_eof)) { 501 | break; 502 | } 503 | 504 | if (isc_close_blob(IB_STATUS, &ib_blob_id.bl_handle)) { 505 | break; 506 | } 507 | RETURN_TRUE; 508 | } while (0); 509 | 510 | _php_ibase_error(); 511 | RETURN_FALSE; 512 | } 513 | /* }}} */ 514 | 515 | /* {{{ proto string ibase_blob_import([ resource link_identifier, ] resource file) 516 | Create blob, copy file in it, and close it */ 517 | PHP_FUNCTION(ibase_blob_import) 518 | { 519 | zval *link = NULL, *file; 520 | int size; 521 | unsigned short b; 522 | ibase_blob ib_blob = { 0, 0 }; 523 | ibase_db_link *ib_link; 524 | ibase_trans *trans = NULL; 525 | char bl_data[IBASE_BLOB_SEG]; 526 | php_stream *stream; 527 | 528 | RESET_ERRMSG; 529 | 530 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "r|r", 531 | (ZEND_NUM_ARGS()-1) ? &link : &file, &file)) { 532 | RETURN_FALSE; 533 | } 534 | 535 | PHP_IBASE_LINK_TRANS(link, ib_link, trans); 536 | 537 | php_stream_from_zval(stream, file); 538 | 539 | do { 540 | if (isc_create_blob(IB_STATUS, &ib_link->handle, &trans->handle, &ib_blob.bl_handle, 541 | &ib_blob.bl_qd)) { 542 | break; 543 | } 544 | 545 | for (size = 0; (b = php_stream_read(stream, bl_data, sizeof(bl_data))); size += b) { 546 | if (isc_put_segment(IB_STATUS, &ib_blob.bl_handle, b, bl_data)) { 547 | break; 548 | } 549 | } 550 | 551 | if (isc_close_blob(IB_STATUS, &ib_blob.bl_handle)) { 552 | break; 553 | } 554 | RETURN_NEW_STR(_php_ibase_quad_to_string(ib_blob.bl_qd)); 555 | } while (0); 556 | 557 | _php_ibase_error(); 558 | RETURN_FALSE; 559 | } 560 | /* }}} */ 561 | 562 | #endif /* HAVE_IBASE */ 563 | -------------------------------------------------------------------------------- /ibase_events.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 7, 8 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 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 | | Authors: Ard Biesheuvel | 16 | | Martin Köditz | 17 | +----------------------------------------------------------------------+ 18 | */ 19 | 20 | #ifdef HAVE_CONFIG_H 21 | #include "config.h" 22 | #endif 23 | 24 | #include "php.h" 25 | 26 | /* 27 | * Since PHP 8 we have troubles building sources on Windows, 28 | * because of missing TSRMLS_FETCH_FROM_CTX and TSRMLS_SET_CTX symbols. 29 | */ 30 | #if PHP_VERSION_ID >= 80000 31 | # define FBIRD_TSRMLS_FETCH_FROM_CTX(user_data) 32 | # define FBIRD_TSRMLS_SET_CTX(user_data) 33 | #else 34 | # define FBIRD_TSRMLS_FETCH_FROM_CTX(user_data) TSRMLS_FETCH_FROM_CTX(user_data) 35 | # define FBIRD_TSRMLS_SET_CTX(user_data) TSRMLS_SET_CTX(user_data) 36 | #endif 37 | 38 | #if HAVE_IBASE 39 | 40 | #include "php_interbase.h" 41 | #include "php_ibase_includes.h" 42 | 43 | static int le_event; 44 | 45 | static void _php_ibase_event_free(unsigned char *event_buf, unsigned char *result_buf) /* {{{ */ 46 | { 47 | isc_free(event_buf); 48 | isc_free(result_buf); 49 | } 50 | /* }}} */ 51 | 52 | void _php_ibase_free_event(ibase_event *event) /* {{{ */ 53 | { 54 | unsigned short i; 55 | 56 | event->state = DEAD; 57 | 58 | if (event->link != NULL) { 59 | ibase_event **node; 60 | 61 | zend_list_delete(event->link_res); 62 | if (event->link->handle != 0 && 63 | isc_cancel_events(IB_STATUS, &event->link->handle, &event->event_id)) { 64 | _php_ibase_error(); 65 | } 66 | 67 | /* delete this event from the link struct */ 68 | for (node = &event->link->event_head; *node != event; node = &(*node)->event_next); 69 | *node = event->event_next; 70 | } 71 | 72 | if (Z_TYPE(event->callback) != IS_UNDEF) { 73 | zval_ptr_dtor(&event->callback); 74 | ZVAL_UNDEF(&event->callback); 75 | 76 | _php_ibase_event_free(event->event_buffer,event->result_buffer); 77 | 78 | for (i = 0; i < event->event_count; ++i) { 79 | if (event->events[i]) { 80 | efree(event->events[i]); 81 | } 82 | } 83 | efree(event->events); 84 | } 85 | } 86 | /* }}} */ 87 | 88 | static void _php_ibase_free_event_rsrc(zend_resource *rsrc) /* {{{ */ 89 | { 90 | ibase_event *e = (ibase_event *) rsrc->ptr; 91 | 92 | _php_ibase_free_event(e); 93 | efree(e); 94 | } 95 | /* }}} */ 96 | 97 | void php_ibase_events_minit(INIT_FUNC_ARGS) /* {{{ */ 98 | { 99 | le_event = zend_register_list_destructors_ex(_php_ibase_free_event_rsrc, NULL, 100 | "interbase event", module_number); 101 | } 102 | /* }}} */ 103 | 104 | static void _php_ibase_event_block(ibase_db_link *ib_link, unsigned short count, 105 | char **events, unsigned short *l, unsigned char **event_buf, unsigned char **result_buf) 106 | { 107 | ISC_STATUS dummy_result[20]; 108 | ISC_ULONG dummy_count[15]; 109 | 110 | /** 111 | * Unfortunately, there's no clean and portable way in C to pass arguments to 112 | * a variadic function if you don't know the number of arguments at compile time. 113 | * (And even if there were a way, the Interbase API doesn't provide a version of 114 | * this function that takes a va_list as an argument) 115 | * 116 | * In this case, the number of arguments is limited to 18 by the underlying API, 117 | * so we can work around it. 118 | */ 119 | 120 | *l = (unsigned short) isc_event_block(event_buf, result_buf, count, events[0], 121 | events[1], events[2], events[3], events[4], events[5], events[6], events[7], 122 | events[8], events[9], events[10], events[11], events[12], events[13], events[14]); 123 | 124 | /** 125 | * Currently, this is the only way to correctly initialize an event buffer. 126 | * This is clearly something that should be fixed, cause the semantics of 127 | * isc_wait_for_event() indicate that it blocks until an event occurs. 128 | * If the Firebird people ever fix this, these lines should be removed, 129 | * otherwise, events will have to fire twice before ibase_wait_event() returns. 130 | */ 131 | 132 | isc_wait_for_event(dummy_result, &ib_link->handle, *l, *event_buf, *result_buf); 133 | isc_event_counts(dummy_count, *l, *event_buf, *result_buf); 134 | } 135 | /* }}} */ 136 | 137 | /* {{{ proto string ibase_wait_event([resource link_identifier,] string event [, string event [, ...]]) 138 | Waits for any one of the passed Interbase events to be posted by the database, and returns its name */ 139 | PHP_FUNCTION(ibase_wait_event) 140 | { 141 | zval *args; 142 | ibase_db_link *ib_link; 143 | int num_args; 144 | unsigned char *event_buffer, *result_buffer; 145 | char *events[15]; 146 | unsigned short i = 0, event_count = 0, buffer_size; 147 | ISC_ULONG occurred_event[15]; 148 | 149 | RESET_ERRMSG; 150 | 151 | /* no more than 15 events */ 152 | if (ZEND_NUM_ARGS() < 1 || ZEND_NUM_ARGS() > 16) { 153 | WRONG_PARAM_COUNT; 154 | } 155 | 156 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &num_args) == FAILURE) { 157 | return; 158 | } 159 | 160 | if (Z_TYPE(args[0]) == IS_RESOURCE) { 161 | if ((ib_link = (ibase_db_link *)zend_fetch_resource2_ex(&args[0], "InterBase link", le_link, le_plink)) == NULL) { 162 | RETURN_FALSE; 163 | } 164 | i = 1; 165 | } else { 166 | if (ZEND_NUM_ARGS() > 15) { 167 | WRONG_PARAM_COUNT; 168 | } 169 | if ((ib_link = (ibase_db_link *)zend_fetch_resource2(IBG(default_link), "InterBase link", le_link, le_plink)) == NULL) { 170 | RETURN_FALSE; 171 | } 172 | } 173 | 174 | for (; i < ZEND_NUM_ARGS(); ++i) { 175 | convert_to_string_ex(&args[i]); 176 | events[event_count++] = Z_STRVAL(args[i]); 177 | } 178 | 179 | /* fills the required data structure with information about the events */ 180 | _php_ibase_event_block(ib_link, event_count, events, &buffer_size, &event_buffer, &result_buffer); 181 | 182 | /* now block until an event occurs */ 183 | if (isc_wait_for_event(IB_STATUS, &ib_link->handle, buffer_size, event_buffer, result_buffer)) { 184 | _php_ibase_error(); 185 | _php_ibase_event_free(event_buffer,result_buffer); 186 | RETURN_FALSE; 187 | } 188 | 189 | /* find out which event occurred */ 190 | isc_event_counts(occurred_event, buffer_size, event_buffer, result_buffer); 191 | for (i = 0; i < event_count; ++i) { 192 | if (occurred_event[i]) { 193 | zend_string *result = zend_string_init(events[i], strlen(events[i]), 0); 194 | _php_ibase_event_free(event_buffer,result_buffer); 195 | RETURN_STR(result); 196 | } 197 | } 198 | 199 | /* If we reach this line, isc_wait_for_event() did return, but we don't know 200 | which event fired. */ 201 | _php_ibase_event_free(event_buffer,result_buffer); 202 | RETURN_FALSE; 203 | } 204 | /* }}} */ 205 | 206 | #if FB_API_VER >= 20 207 | #define PHP_ISC_CALLBACK ISC_EVENT_CALLBACK 208 | static ISC_EVENT_CALLBACK _php_ibase_callback(ibase_event *event, /* {{{ */ 209 | ISC_USHORT buffer_size, ISC_UCHAR *result_buf) 210 | #else 211 | #define PHP_ISC_CALLBACK isc_callback 212 | static isc_callback _php_ibase_callback(ibase_event *event, /* {{{ */ 213 | unsigned short buffer_size, unsigned char *result_buf) 214 | #endif 215 | { 216 | /* this function is called asynchronously by the Interbase client library. */ 217 | FBIRD_TSRMLS_FETCH_FROM_CTX(event->thread_ctx); 218 | 219 | /** 220 | * The callback function is called when the event is first registered and when the event 221 | * is cancelled. I consider this is a bug. By clearing event->callback first and setting 222 | * it to -1 later, we make sure nothing happens if no event was actually posted. 223 | */ 224 | switch (event->state) { 225 | unsigned short i; 226 | ISC_ULONG occurred_event[15]; 227 | zval return_value, args[2]; 228 | 229 | default: /* == DEAD */ 230 | break; 231 | case ACTIVE: 232 | /* copy the updated results into the result buffer */ 233 | memcpy(event->result_buffer, result_buf, buffer_size); 234 | 235 | ZVAL_RES(&args[1], event->link_res); 236 | 237 | /* find out which event occurred */ 238 | isc_event_counts(occurred_event, buffer_size, event->event_buffer, event->result_buffer); 239 | for (i = 0; i < event->event_count; ++i) { 240 | if (occurred_event[i]) { 241 | ZVAL_STRING(&args[0], event->events[i]); 242 | //efree(event->events[i]); 243 | break; 244 | } 245 | } 246 | 247 | /* call the callback provided by the user */ 248 | if (SUCCESS != call_user_function(NULL, NULL, 249 | &event->callback, &return_value, 2, args)) { 250 | _php_ibase_module_error("Error calling callback %s", Z_STRVAL(event->callback)); 251 | break; 252 | } 253 | 254 | if (Z_TYPE(return_value) == IS_FALSE) { 255 | event->state = DEAD; 256 | break; 257 | } 258 | case NEW: 259 | /* re-register the event */ 260 | if (isc_que_events(IB_STATUS, &event->link->handle, &event->event_id, buffer_size, 261 | event->event_buffer,(PHP_ISC_CALLBACK)_php_ibase_callback, (void *)event)) { 262 | 263 | _php_ibase_error(); 264 | } 265 | event->state = ACTIVE; 266 | } 267 | return 0; 268 | } 269 | /* }}} */ 270 | 271 | /* {{{ proto resource ibase_set_event_handler([resource link_identifier,] callback handler, string event [, string event [, ...]]) 272 | Register the callback for handling each of the named events */ 273 | PHP_FUNCTION(ibase_set_event_handler) 274 | { 275 | /** 276 | * The callback passed to this function should take an event name (string) and a 277 | * link resource id (int) as arguments. The value returned from the function is 278 | * used to determine if the event handler should remain set. 279 | */ 280 | zval *args, *cb_arg; 281 | ibase_db_link *ib_link; 282 | ibase_event *event; 283 | unsigned short i = 1, buffer_size; 284 | int num_args; 285 | zend_resource *link_res; 286 | 287 | RESET_ERRMSG; 288 | 289 | /* Minimum and maximum number of arguments allowed */ 290 | if (ZEND_NUM_ARGS() < 2 || ZEND_NUM_ARGS() > 17) { 291 | WRONG_PARAM_COUNT; 292 | } 293 | 294 | if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &num_args) == FAILURE) { 295 | return; 296 | } 297 | 298 | /* get a working link */ 299 | if (Z_TYPE(args[0]) != IS_STRING) { 300 | /* resource, callback, event_1 [, ... event_15] 301 | * No more than 15 events 302 | */ 303 | if (ZEND_NUM_ARGS() < 3 || ZEND_NUM_ARGS() > 17) { 304 | WRONG_PARAM_COUNT; 305 | } 306 | 307 | cb_arg = &args[1]; 308 | i = 2; 309 | 310 | if ((ib_link = (ibase_db_link *)zend_fetch_resource2_ex(&args[0], "InterBase link", le_link, le_plink)) == NULL) { 311 | RETURN_FALSE; 312 | } 313 | 314 | link_res = Z_RES(args[0]); 315 | 316 | } else { 317 | /* callback, event_1 [, ... event_15] 318 | * No more than 15 events 319 | */ 320 | if (ZEND_NUM_ARGS() < 2 || ZEND_NUM_ARGS() > 16) { 321 | WRONG_PARAM_COUNT; 322 | } 323 | 324 | cb_arg = &args[0]; 325 | 326 | if ((ib_link = (ibase_db_link *)zend_fetch_resource2(IBG(default_link), "InterBase link", le_link, le_plink)) == NULL) { 327 | RETURN_FALSE; 328 | } 329 | link_res = IBG(default_link); 330 | } 331 | 332 | /* get the callback */ 333 | if (!zend_is_callable(cb_arg, 0, NULL)) { 334 | zend_string *cb_name = zend_get_callable_name(cb_arg); 335 | _php_ibase_module_error("Callback argument %s is not a callable function", ZSTR_VAL(cb_name)); 336 | zend_string_release_ex(cb_name, 0); 337 | RETURN_FALSE; 338 | } 339 | 340 | /* allocate the event resource */ 341 | event = (ibase_event *) safe_emalloc(sizeof(ibase_event), 1, 0); 342 | FBIRD_TSRMLS_SET_CTX(event->thread_ctx); 343 | event->link_res = link_res; 344 | GC_ADDREF(link_res); 345 | event->link = ib_link; 346 | event->event_count = 0; 347 | event->state = NEW; 348 | event->events = (char **) safe_emalloc(sizeof(char *), 15, 0); 349 | 350 | ZVAL_DUP(&event->callback, cb_arg); 351 | 352 | for (; i < 15; ++i) { 353 | if (i < ZEND_NUM_ARGS()) { 354 | convert_to_string_ex(&args[i]); 355 | event->events[event->event_count++] = estrdup(Z_STRVAL(args[i])); 356 | } else { 357 | event->events[i] = NULL; 358 | } 359 | } 360 | 361 | /* fills the required data structure with information about the events */ 362 | _php_ibase_event_block(ib_link, event->event_count, event->events, 363 | &buffer_size, &event->event_buffer, &event->result_buffer); 364 | 365 | /* now register the events with the Interbase API */ 366 | if (isc_que_events(IB_STATUS, &ib_link->handle, &event->event_id, buffer_size, 367 | event->event_buffer,(PHP_ISC_CALLBACK)_php_ibase_callback, (void *)event)) { 368 | 369 | _php_ibase_error(); 370 | efree(event); 371 | RETURN_FALSE; 372 | } 373 | 374 | event->event_next = ib_link->event_head; 375 | ib_link->event_head = event; 376 | 377 | RETVAL_RES(zend_register_resource(event, le_event)); 378 | Z_TRY_ADDREF_P(return_value); 379 | } 380 | /* }}} */ 381 | 382 | /* {{{ proto bool ibase_free_event_handler(resource event) 383 | Frees the event handler set by ibase_set_event_handler() */ 384 | PHP_FUNCTION(ibase_free_event_handler) 385 | { 386 | zval *event_arg; 387 | 388 | RESET_ERRMSG; 389 | 390 | if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "r", &event_arg)) { 391 | ibase_event *event; 392 | 393 | event = (ibase_event *)zend_fetch_resource_ex(event_arg, "Interbase event", le_event); 394 | 395 | event->state = DEAD; 396 | 397 | zend_list_delete(Z_RES_P(event_arg)); 398 | RETURN_TRUE; 399 | } else { 400 | RETURN_FALSE; 401 | } 402 | } 403 | /* }}} */ 404 | 405 | #endif /* HAVE_IBASE */ 406 | -------------------------------------------------------------------------------- /ibase_service.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 7, 8 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 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 | | Authors: Jouni Ahto | 16 | | Andrew Avdeev | 17 | | Ard Biesheuvel | 18 | | Martin Koeditz | 19 | | others | 20 | +----------------------------------------------------------------------+ 21 | | You'll find history on Github | 22 | | https://github.com/FirebirdSQL/php-firebird/commits/master | 23 | +----------------------------------------------------------------------+ 24 | */ 25 | 26 | #ifdef HAVE_CONFIG_H 27 | #include "config.h" 28 | #endif 29 | 30 | #include "php.h" 31 | 32 | #if HAVE_IBASE 33 | 34 | #include "php_interbase.h" 35 | #include "php_ibase_includes.h" 36 | 37 | typedef struct { 38 | isc_svc_handle handle; 39 | char *hostname; 40 | char *username; 41 | zend_resource *res; 42 | } ibase_service; 43 | 44 | static int le_service; 45 | 46 | static void _php_ibase_free_service(zend_resource *rsrc) /* {{{ */ 47 | { 48 | ibase_service *sv = (ibase_service *) rsrc->ptr; 49 | 50 | if (isc_service_detach(IB_STATUS, &sv->handle)) { 51 | _php_ibase_error(); 52 | } 53 | 54 | if (sv->hostname) { 55 | efree(sv->hostname); 56 | } 57 | if (sv->username) { 58 | efree(sv->username); 59 | } 60 | 61 | efree(sv); 62 | } 63 | /* }}} */ 64 | 65 | /* the svc api seems to get confused after an error has occurred, 66 | so invalidate the handle on errors */ 67 | #define IBASE_SVC_ERROR(svm) \ 68 | do { zend_list_delete(svm->res); _php_ibase_error(); } while (0) 69 | 70 | 71 | void php_ibase_service_minit(INIT_FUNC_ARGS) /* {{{ */ 72 | { 73 | le_service = zend_register_list_destructors_ex(_php_ibase_free_service, NULL, 74 | "interbase service manager handle", module_number); 75 | 76 | /* backup options */ 77 | REGISTER_LONG_CONSTANT("IBASE_BKP_IGNORE_CHECKSUMS", isc_spb_bkp_ignore_checksums, CONST_PERSISTENT); 78 | REGISTER_LONG_CONSTANT("IBASE_BKP_IGNORE_LIMBO", isc_spb_bkp_ignore_limbo, CONST_PERSISTENT); 79 | REGISTER_LONG_CONSTANT("IBASE_BKP_METADATA_ONLY", isc_spb_bkp_metadata_only, CONST_PERSISTENT); 80 | REGISTER_LONG_CONSTANT("IBASE_BKP_NO_GARBAGE_COLLECT", isc_spb_bkp_no_garbage_collect, CONST_PERSISTENT); 81 | REGISTER_LONG_CONSTANT("IBASE_BKP_OLD_DESCRIPTIONS", isc_spb_bkp_old_descriptions, CONST_PERSISTENT); 82 | REGISTER_LONG_CONSTANT("IBASE_BKP_NON_TRANSPORTABLE", isc_spb_bkp_non_transportable, CONST_PERSISTENT); 83 | REGISTER_LONG_CONSTANT("IBASE_BKP_CONVERT", isc_spb_bkp_convert, CONST_PERSISTENT); 84 | 85 | /* restore options */ 86 | REGISTER_LONG_CONSTANT("IBASE_RES_DEACTIVATE_IDX", isc_spb_res_deactivate_idx, CONST_PERSISTENT); 87 | REGISTER_LONG_CONSTANT("IBASE_RES_NO_SHADOW", isc_spb_res_no_shadow, CONST_PERSISTENT); 88 | REGISTER_LONG_CONSTANT("IBASE_RES_NO_VALIDITY", isc_spb_res_no_validity, CONST_PERSISTENT); 89 | REGISTER_LONG_CONSTANT("IBASE_RES_ONE_AT_A_TIME", isc_spb_res_one_at_a_time, CONST_PERSISTENT); 90 | REGISTER_LONG_CONSTANT("IBASE_RES_REPLACE", isc_spb_res_replace, CONST_PERSISTENT); 91 | REGISTER_LONG_CONSTANT("IBASE_RES_CREATE", isc_spb_res_create, CONST_PERSISTENT); 92 | REGISTER_LONG_CONSTANT("IBASE_RES_USE_ALL_SPACE", isc_spb_res_use_all_space, CONST_PERSISTENT); 93 | 94 | /* manage options */ 95 | REGISTER_LONG_CONSTANT("IBASE_PRP_PAGE_BUFFERS", isc_spb_prp_page_buffers, CONST_PERSISTENT); 96 | REGISTER_LONG_CONSTANT("IBASE_PRP_SWEEP_INTERVAL", isc_spb_prp_sweep_interval, CONST_PERSISTENT); 97 | REGISTER_LONG_CONSTANT("IBASE_PRP_SHUTDOWN_DB", isc_spb_prp_shutdown_db, CONST_PERSISTENT); 98 | REGISTER_LONG_CONSTANT("IBASE_PRP_DENY_NEW_TRANSACTIONS", isc_spb_prp_deny_new_transactions, CONST_PERSISTENT); 99 | REGISTER_LONG_CONSTANT("IBASE_PRP_DENY_NEW_ATTACHMENTS", isc_spb_prp_deny_new_attachments, CONST_PERSISTENT); 100 | REGISTER_LONG_CONSTANT("IBASE_PRP_RESERVE_SPACE", isc_spb_prp_reserve_space, CONST_PERSISTENT); 101 | REGISTER_LONG_CONSTANT("IBASE_PRP_RES_USE_FULL", isc_spb_prp_res_use_full, CONST_PERSISTENT); 102 | REGISTER_LONG_CONSTANT("IBASE_PRP_RES", isc_spb_prp_res, CONST_PERSISTENT); 103 | REGISTER_LONG_CONSTANT("IBASE_PRP_WRITE_MODE", isc_spb_prp_write_mode, CONST_PERSISTENT); 104 | REGISTER_LONG_CONSTANT("IBASE_PRP_WM_ASYNC", isc_spb_prp_wm_async, CONST_PERSISTENT); 105 | REGISTER_LONG_CONSTANT("IBASE_PRP_WM_SYNC", isc_spb_prp_wm_sync, CONST_PERSISTENT); 106 | REGISTER_LONG_CONSTANT("IBASE_PRP_ACCESS_MODE", isc_spb_prp_access_mode, CONST_PERSISTENT); 107 | REGISTER_LONG_CONSTANT("IBASE_PRP_AM_READONLY", isc_spb_prp_am_readonly, CONST_PERSISTENT); 108 | REGISTER_LONG_CONSTANT("IBASE_PRP_AM_READWRITE", isc_spb_prp_am_readwrite, CONST_PERSISTENT); 109 | REGISTER_LONG_CONSTANT("IBASE_PRP_SET_SQL_DIALECT", isc_spb_prp_set_sql_dialect, CONST_PERSISTENT); 110 | REGISTER_LONG_CONSTANT("IBASE_PRP_ACTIVATE", isc_spb_prp_activate, CONST_PERSISTENT); 111 | REGISTER_LONG_CONSTANT("IBASE_PRP_DB_ONLINE", isc_spb_prp_db_online, CONST_PERSISTENT); 112 | 113 | /* repair options */ 114 | REGISTER_LONG_CONSTANT("IBASE_RPR_CHECK_DB", isc_spb_rpr_check_db, CONST_PERSISTENT); 115 | REGISTER_LONG_CONSTANT("IBASE_RPR_IGNORE_CHECKSUM", isc_spb_rpr_ignore_checksum, CONST_PERSISTENT); 116 | REGISTER_LONG_CONSTANT("IBASE_RPR_KILL_SHADOWS", isc_spb_rpr_kill_shadows, CONST_PERSISTENT); 117 | REGISTER_LONG_CONSTANT("IBASE_RPR_MEND_DB", isc_spb_rpr_mend_db, CONST_PERSISTENT); 118 | REGISTER_LONG_CONSTANT("IBASE_RPR_VALIDATE_DB", isc_spb_rpr_validate_db, CONST_PERSISTENT); 119 | REGISTER_LONG_CONSTANT("IBASE_RPR_FULL", isc_spb_rpr_full, CONST_PERSISTENT); 120 | REGISTER_LONG_CONSTANT("IBASE_RPR_SWEEP_DB", isc_spb_rpr_sweep_db, CONST_PERSISTENT); 121 | 122 | /* db info arguments */ 123 | REGISTER_LONG_CONSTANT("IBASE_STS_DATA_PAGES", isc_spb_sts_data_pages, CONST_PERSISTENT); 124 | REGISTER_LONG_CONSTANT("IBASE_STS_DB_LOG", isc_spb_sts_db_log, CONST_PERSISTENT); 125 | REGISTER_LONG_CONSTANT("IBASE_STS_HDR_PAGES", isc_spb_sts_hdr_pages, CONST_PERSISTENT); 126 | REGISTER_LONG_CONSTANT("IBASE_STS_IDX_PAGES", isc_spb_sts_idx_pages, CONST_PERSISTENT); 127 | REGISTER_LONG_CONSTANT("IBASE_STS_SYS_RELATIONS", isc_spb_sts_sys_relations, CONST_PERSISTENT); 128 | 129 | /* server info arguments */ 130 | REGISTER_LONG_CONSTANT("IBASE_SVC_SERVER_VERSION", isc_info_svc_server_version, CONST_PERSISTENT); 131 | REGISTER_LONG_CONSTANT("IBASE_SVC_IMPLEMENTATION", isc_info_svc_implementation, CONST_PERSISTENT); 132 | REGISTER_LONG_CONSTANT("IBASE_SVC_GET_ENV", isc_info_svc_get_env, CONST_PERSISTENT); 133 | REGISTER_LONG_CONSTANT("IBASE_SVC_GET_ENV_LOCK", isc_info_svc_get_env_lock, CONST_PERSISTENT); 134 | REGISTER_LONG_CONSTANT("IBASE_SVC_GET_ENV_MSG", isc_info_svc_get_env_msg, CONST_PERSISTENT); 135 | REGISTER_LONG_CONSTANT("IBASE_SVC_USER_DBPATH", isc_info_svc_user_dbpath, CONST_PERSISTENT); 136 | REGISTER_LONG_CONSTANT("IBASE_SVC_SVR_DB_INFO", isc_info_svc_svr_db_info, CONST_PERSISTENT); 137 | REGISTER_LONG_CONSTANT("IBASE_SVC_GET_USERS", isc_info_svc_get_users, CONST_PERSISTENT); 138 | } 139 | /* }}} */ 140 | 141 | static void _php_ibase_user(INTERNAL_FUNCTION_PARAMETERS, char operation) /* {{{ */ 142 | { 143 | /* user = 0, password = 1, first_name = 2, middle_name = 3, last_name = 4 */ 144 | static char const user_flags[] = { isc_spb_sec_username, isc_spb_sec_password, 145 | isc_spb_sec_firstname, isc_spb_sec_middlename, isc_spb_sec_lastname }; 146 | char buf[128], *args[] = { NULL, NULL, NULL, NULL, NULL }; 147 | int i, args_len[] = { 0, 0, 0, 0, 0 }; 148 | unsigned short spb_len = 1; 149 | zval *res; 150 | ibase_service *svm; 151 | 152 | RESET_ERRMSG; 153 | 154 | if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), 155 | (operation == isc_action_svc_delete_user) ? "rs" : "rss|sss", 156 | &res, &args[0], &args_len[0], &args[1], &args_len[1], &args[2], &args_len[2], 157 | &args[3], &args_len[3], &args[4], &args_len[4])) { 158 | RETURN_FALSE; 159 | } 160 | 161 | svm = (ibase_service *)zend_fetch_resource_ex(res, "Interbase service manager handle", 162 | le_service); 163 | 164 | buf[0] = operation; 165 | 166 | for (i = 0; i < sizeof(user_flags); ++i) { 167 | if (args[i] != NULL) { 168 | int chunk = slprintf(&buf[spb_len], sizeof(buf) - spb_len, "%c%c%c%s", 169 | user_flags[i], (char)args_len[i], (char)(args_len[i] >> 8), args[i]); 170 | 171 | if ((spb_len + chunk) > sizeof(buf) || chunk <= 0) { 172 | _php_ibase_module_error("Internal error: insufficient buffer space for SPB (%d)", spb_len); 173 | RETURN_FALSE; 174 | } 175 | spb_len += chunk; 176 | } 177 | } 178 | 179 | /* now start the job */ 180 | if (isc_service_start(IB_STATUS, &svm->handle, NULL, spb_len, buf)) { 181 | IBASE_SVC_ERROR(svm); 182 | RETURN_FALSE; 183 | } 184 | 185 | RETURN_TRUE; 186 | } 187 | /* }}} */ 188 | 189 | /* {{{ proto bool ibase_add_user(resource service_handle, string user_name, string password [, string first_name [, string middle_name [, string last_name]]]) 190 | Add a user to security database */ 191 | PHP_FUNCTION(ibase_add_user) 192 | { 193 | _php_ibase_user(INTERNAL_FUNCTION_PARAM_PASSTHRU, isc_action_svc_add_user); 194 | } 195 | /* }}} */ 196 | 197 | /* {{{ proto bool ibase_modify_user(resource service_handle, string user_name, string password [, string first_name [, string middle_name [, string last_name]]]) 198 | Modify a user in security database */ 199 | PHP_FUNCTION(ibase_modify_user) 200 | { 201 | _php_ibase_user(INTERNAL_FUNCTION_PARAM_PASSTHRU, isc_action_svc_modify_user); 202 | } 203 | /* }}} */ 204 | 205 | /* {{{ proto bool ibase_delete_user(resource service_handle, string user_name, string password [, string first_name [, string middle_name [, string last_name]]]) 206 | Delete a user from security database */ 207 | PHP_FUNCTION(ibase_delete_user) 208 | { 209 | _php_ibase_user(INTERNAL_FUNCTION_PARAM_PASSTHRU, isc_action_svc_delete_user); 210 | } 211 | /* }}} */ 212 | 213 | /* {{{ proto resource ibase_service_attach(string host, string dba_username, string dba_password) 214 | Connect to the service manager */ 215 | PHP_FUNCTION(ibase_service_attach) 216 | { 217 | size_t hlen, ulen, plen, spb_len; 218 | ibase_service *svm; 219 | char buf[128], *host, *user, *pass, *loc; 220 | isc_svc_handle handle = 0; 221 | 222 | RESET_ERRMSG; 223 | 224 | if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "sss", 225 | &host, &hlen, &user, &ulen, &pass, &plen)) { 226 | 227 | RETURN_FALSE; 228 | } 229 | 230 | /* construct the spb, hack the service name into it as well */ 231 | spb_len = slprintf(buf, sizeof(buf), "%c%c%c%c%s%c%c%s" "%s:service_mgr", 232 | isc_spb_version, isc_spb_current_version, isc_spb_user_name, (char)ulen, 233 | user, isc_spb_password, (char)plen, pass, host); 234 | 235 | if (spb_len > sizeof(buf) || spb_len == -1) { 236 | _php_ibase_module_error("Internal error: insufficient buffer space for SPB (%zd)", spb_len); 237 | RETURN_FALSE; 238 | } 239 | 240 | spb_len -= hlen + 12; 241 | loc = buf + spb_len; /* points to %s:service_mgr part */ 242 | 243 | /* attach to the service manager */ 244 | if (isc_service_attach(IB_STATUS, 0, loc, &handle, (unsigned short)spb_len, buf)) { 245 | _php_ibase_error(); 246 | RETURN_FALSE; 247 | } 248 | 249 | svm = (ibase_service*)emalloc(sizeof(ibase_service)); 250 | svm->handle = handle; 251 | svm->hostname = estrdup(host); 252 | svm->username = estrdup(user); 253 | 254 | RETVAL_RES(zend_register_resource(svm, le_service)); 255 | Z_TRY_ADDREF_P(return_value); 256 | svm->res = Z_RES_P(return_value); 257 | } 258 | /* }}} */ 259 | 260 | /* {{{ proto bool ibase_service_detach(resource service_handle) 261 | Disconnect from the service manager */ 262 | PHP_FUNCTION(ibase_service_detach) 263 | { 264 | zval *res; 265 | 266 | RESET_ERRMSG; 267 | 268 | if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "r", &res)) { 269 | RETURN_FALSE; 270 | } 271 | 272 | zend_list_delete(Z_RES_P(res)); 273 | 274 | RETURN_TRUE; 275 | } 276 | /* }}} */ 277 | 278 | static void _php_ibase_service_query(INTERNAL_FUNCTION_PARAMETERS, /* {{{ */ 279 | ibase_service *svm, char info_action) 280 | { 281 | static char spb[] = { isc_info_svc_timeout, 10, 0, 0, 0 }; 282 | 283 | char res_buf[400], *result, *heap_buf = NULL, *heap_p; 284 | zend_long heap_buf_size = 200, line_len; 285 | 286 | /* info about users requires an action first */ 287 | if (info_action == isc_info_svc_get_users) { 288 | static char action[] = { isc_action_svc_display_user }; 289 | 290 | if (isc_service_start(IB_STATUS, &svm->handle, NULL, sizeof(action), action)) { 291 | IBASE_SVC_ERROR(svm); 292 | RETURN_FALSE; 293 | } 294 | } 295 | 296 | query_loop: 297 | result = res_buf; 298 | 299 | if (isc_service_query(IB_STATUS, &svm->handle, NULL, sizeof(spb), spb, 300 | 1, &info_action, sizeof(res_buf), res_buf)) { 301 | 302 | IBASE_SVC_ERROR(svm); 303 | RETURN_FALSE; 304 | } 305 | while (*result != isc_info_end) { 306 | switch (*result++) { 307 | default: 308 | RETURN_FALSE; 309 | 310 | case isc_info_svc_line: 311 | if (! (line_len = isc_vax_integer(result, 2))) { 312 | /* done */ 313 | if (heap_buf) { 314 | RETVAL_STRING(heap_buf); 315 | efree(heap_buf); 316 | return; 317 | } else { 318 | RETURN_TRUE; 319 | } 320 | } 321 | if (!heap_buf || (heap_p - heap_buf + line_len +2) > heap_buf_size) { 322 | zend_long res_size = heap_buf ? heap_p - heap_buf : 0; 323 | 324 | while (heap_buf_size < (res_size + line_len +2)) { 325 | heap_buf_size *= 2; 326 | } 327 | heap_buf = (char*) erealloc(heap_buf, heap_buf_size); 328 | heap_p = heap_buf + res_size; 329 | } 330 | result += 2; 331 | *(result+line_len) = 0; 332 | snprintf(heap_p, heap_buf_size - (heap_p - heap_buf), "%s\n", result); 333 | heap_p += line_len +1; 334 | goto query_loop; /* repeat until result is exhausted */ 335 | 336 | case isc_info_svc_server_version: 337 | case isc_info_svc_implementation: 338 | case isc_info_svc_get_env: 339 | case isc_info_svc_get_env_lock: 340 | case isc_info_svc_get_env_msg: 341 | case isc_info_svc_user_dbpath: 342 | RETURN_STRINGL(result + 2, isc_vax_integer(result, 2)); 343 | 344 | case isc_info_svc_svr_db_info: 345 | array_init(return_value); 346 | 347 | do { 348 | switch (*result++) { 349 | int len; 350 | 351 | case isc_spb_num_att: 352 | add_assoc_long(return_value, "attachments", isc_vax_integer(result,4)); 353 | result += 4; 354 | break; 355 | 356 | case isc_spb_num_db: 357 | add_assoc_long(return_value, "databases", isc_vax_integer(result,4)); 358 | result += 4; 359 | break; 360 | 361 | case isc_spb_dbname: 362 | len = isc_vax_integer(result,2); 363 | add_next_index_stringl(return_value, result +2, len); 364 | result += len+2; 365 | } 366 | } while (*result != isc_info_flag_end); 367 | return; 368 | 369 | case isc_info_svc_get_users: { 370 | zval user; 371 | array_init(return_value); 372 | 373 | while (*result != isc_info_end) { 374 | 375 | switch (*result++) { 376 | int len; 377 | 378 | case isc_spb_sec_username: 379 | /* it appears that the username is always first */ 380 | array_init(&user); 381 | add_next_index_zval(return_value, &user); 382 | 383 | len = isc_vax_integer(result,2); 384 | add_assoc_stringl(&user, "user_name", result +2, len); 385 | result += len+2; 386 | break; 387 | 388 | case isc_spb_sec_firstname: 389 | len = isc_vax_integer(result,2); 390 | add_assoc_stringl(&user, "first_name", result +2, len); 391 | result += len+2; 392 | break; 393 | 394 | case isc_spb_sec_middlename: 395 | len = isc_vax_integer(result,2); 396 | add_assoc_stringl(&user, "middle_name", result +2, len); 397 | result += len+2; 398 | break; 399 | 400 | case isc_spb_sec_lastname: 401 | len = isc_vax_integer(result,2); 402 | add_assoc_stringl(&user, "last_name", result +2, len); 403 | result += len+2; 404 | break; 405 | 406 | case isc_spb_sec_userid: 407 | add_assoc_long(&user, "user_id", isc_vax_integer(result, 4)); 408 | result += 4; 409 | break; 410 | 411 | case isc_spb_sec_groupid: 412 | add_assoc_long(&user, "group_id", isc_vax_integer(result, 4)); 413 | result += 4; 414 | break; 415 | } 416 | } 417 | return; 418 | } 419 | } 420 | } 421 | } 422 | /* }}} */ 423 | 424 | static void _php_ibase_backup_restore(INTERNAL_FUNCTION_PARAMETERS, char operation) /* {{{ */ 425 | { 426 | /** 427 | * It appears that the service API is a little bit confused about which flag 428 | * to use for the source and destination in the case of a restore operation. 429 | * When passing the backup file as isc_spb_dbname and the destination db as 430 | * bpk_file, things work well. 431 | */ 432 | zval *res; 433 | char *db, *bk, buf[200]; 434 | size_t dblen, bklen, spb_len; 435 | zend_long opts = 0; 436 | zend_bool verbose = 0; 437 | ibase_service *svm; 438 | 439 | RESET_ERRMSG; 440 | 441 | if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "rss|lb", 442 | &res, &db, &dblen, &bk, &bklen, &opts, &verbose)) { 443 | RETURN_FALSE; 444 | } 445 | 446 | svm = (ibase_service *)zend_fetch_resource_ex(res, 447 | "Interbase service manager handle", le_service); 448 | 449 | /* fill the param buffer */ 450 | spb_len = slprintf(buf, sizeof(buf), "%c%c%c%c%s%c%c%c%s%c%c%c%c%c", 451 | operation, isc_spb_dbname, (char)dblen, (char)(dblen >> 8), db, 452 | isc_spb_bkp_file, (char)bklen, (char)(bklen >> 8), bk, isc_spb_options, 453 | (char)opts,(char)(opts >> 8), (char)(opts >> 16), (char)(opts >> 24)); 454 | 455 | if (verbose) { 456 | buf[spb_len++] = isc_spb_verbose; 457 | } 458 | 459 | if (spb_len > sizeof(buf) || spb_len <= 0) { 460 | _php_ibase_module_error("Internal error: insufficient buffer space for SPB (%zd)", spb_len); 461 | RETURN_FALSE; 462 | } 463 | 464 | /* now start the backup/restore job */ 465 | if (isc_service_start(IB_STATUS, &svm->handle, NULL, (unsigned short)spb_len, buf)) { 466 | IBASE_SVC_ERROR(svm); 467 | RETURN_FALSE; 468 | } 469 | 470 | if (!verbose) { 471 | RETURN_TRUE; 472 | } else { 473 | _php_ibase_service_query(INTERNAL_FUNCTION_PARAM_PASSTHRU, svm, isc_info_svc_line); 474 | } 475 | } 476 | /* }}} */ 477 | 478 | /* {{{ proto mixed ibase_backup(resource service_handle, string source_db, string dest_file [, int options [, bool verbose]]) 479 | Initiates a backup task in the service manager and returns immediately */ 480 | PHP_FUNCTION(ibase_backup) 481 | { 482 | _php_ibase_backup_restore(INTERNAL_FUNCTION_PARAM_PASSTHRU, isc_action_svc_backup); 483 | } 484 | /* }}} */ 485 | 486 | /* {{{ proto mixed ibase_restore(resource service_handle, string source_file, string dest_db [, int options [, bool verbose]]) 487 | Initiates a restore task in the service manager and returns immediately */ 488 | PHP_FUNCTION(ibase_restore) 489 | { 490 | _php_ibase_backup_restore(INTERNAL_FUNCTION_PARAM_PASSTHRU, isc_action_svc_restore); 491 | } 492 | /* }}} */ 493 | 494 | static void _php_ibase_service_action(INTERNAL_FUNCTION_PARAMETERS, char svc_action) /* {{{ */ 495 | { 496 | zval *res; 497 | char buf[128], *db; 498 | size_t dblen; 499 | int spb_len; 500 | zend_long action, argument = 0; 501 | ibase_service *svm; 502 | 503 | RESET_ERRMSG; 504 | 505 | if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "rsl|l", 506 | &res, &db, &dblen, &action, &argument)) { 507 | RETURN_FALSE; 508 | } 509 | 510 | svm = (ibase_service *)zend_fetch_resource_ex(res, 511 | "Interbase service manager handle", le_service); 512 | 513 | if (svc_action == isc_action_svc_db_stats) { 514 | switch (action) { 515 | default: 516 | goto unknown_option; 517 | 518 | case isc_spb_sts_data_pages: 519 | case isc_spb_sts_db_log: 520 | case isc_spb_sts_hdr_pages: 521 | case isc_spb_sts_idx_pages: 522 | case isc_spb_sts_sys_relations: 523 | goto options_argument; 524 | } 525 | } else { 526 | /* these actions all expect different types of arguments */ 527 | switch (action) { 528 | default: 529 | unknown_option: 530 | _php_ibase_module_error("Unrecognised option (" ZEND_LONG_FMT ")", action); 531 | RETURN_FALSE; 532 | 533 | case isc_spb_rpr_check_db: 534 | case isc_spb_rpr_ignore_checksum: 535 | case isc_spb_rpr_kill_shadows: 536 | case isc_spb_rpr_mend_db: 537 | case isc_spb_rpr_validate_db: 538 | case isc_spb_rpr_sweep_db: 539 | svc_action = isc_action_svc_repair; 540 | 541 | case isc_spb_prp_activate: 542 | case isc_spb_prp_db_online: 543 | options_argument: 544 | argument |= action; 545 | action = isc_spb_options; 546 | 547 | case isc_spb_prp_page_buffers: 548 | case isc_spb_prp_sweep_interval: 549 | case isc_spb_prp_shutdown_db: 550 | case isc_spb_prp_deny_new_transactions: 551 | case isc_spb_prp_deny_new_attachments: 552 | case isc_spb_prp_set_sql_dialect: 553 | spb_len = slprintf(buf, sizeof(buf), "%c%c%c%c%s%c%c%c%c%c", 554 | svc_action, isc_spb_dbname, (char)dblen, (char)(dblen >> 8), db, 555 | (char)action, (char)argument, (char)(argument >> 8), (char)(argument >> 16), 556 | (char)(argument >> 24)); 557 | break; 558 | 559 | case isc_spb_prp_reserve_space: 560 | case isc_spb_prp_write_mode: 561 | case isc_spb_prp_access_mode: 562 | spb_len = slprintf(buf, sizeof(buf), "%c%c%c%c%s%c%c", 563 | isc_action_svc_properties, isc_spb_dbname, (char)dblen, (char)(dblen >> 8), 564 | db, (char)action, (char)argument); 565 | } 566 | } 567 | 568 | if (spb_len > sizeof(buf) || spb_len == -1) { 569 | _php_ibase_module_error("Internal error: insufficient buffer space for SPB (%d)", spb_len); 570 | RETURN_FALSE; 571 | } 572 | 573 | if (isc_service_start(IB_STATUS, &svm->handle, NULL, (unsigned short)spb_len, buf)) { 574 | IBASE_SVC_ERROR(svm); 575 | RETURN_FALSE; 576 | } 577 | 578 | if (svc_action == isc_action_svc_db_stats) { 579 | _php_ibase_service_query(INTERNAL_FUNCTION_PARAM_PASSTHRU, svm, isc_info_svc_line); 580 | } else { 581 | RETURN_TRUE; 582 | } 583 | } 584 | /* }}} */ 585 | 586 | /* {{{ proto bool ibase_maintain_db(resource service_handle, string db, int action [, int argument]) 587 | Execute a maintenance command on the database server */ 588 | PHP_FUNCTION(ibase_maintain_db) 589 | { 590 | _php_ibase_service_action(INTERNAL_FUNCTION_PARAM_PASSTHRU, isc_action_svc_properties); 591 | } 592 | /* }}} */ 593 | 594 | /* {{{ proto string ibase_db_info(resource service_handle, string db, int action [, int argument]) 595 | Request statistics about a database */ 596 | PHP_FUNCTION(ibase_db_info) 597 | { 598 | _php_ibase_service_action(INTERNAL_FUNCTION_PARAM_PASSTHRU, isc_action_svc_db_stats); 599 | } 600 | /* }}} */ 601 | 602 | /* {{{ proto string ibase_server_info(resource service_handle, int action) 603 | Request information about a database server */ 604 | PHP_FUNCTION(ibase_server_info) 605 | { 606 | zval *res; 607 | zend_long action; 608 | ibase_service *svm; 609 | 610 | RESET_ERRMSG; 611 | 612 | if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "rl", &res, &action)) { 613 | RETURN_FALSE; 614 | } 615 | 616 | svm = (ibase_service *)zend_fetch_resource_ex(res, 617 | "Interbase service manager handle", le_service); 618 | 619 | _php_ibase_service_query(INTERNAL_FUNCTION_PARAM_PASSTHRU, svm, (char)action); 620 | } 621 | /* }}} */ 622 | 623 | #else 624 | 625 | void php_ibase_register_service_constants(INIT_FUNC_ARGS) { /* nop */ } 626 | 627 | #endif /* HAVE_IBASE */ 628 | -------------------------------------------------------------------------------- /pdo_firebird_utils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | Copyright (c) The PHP Group | 4 | +----------------------------------------------------------------------+ 5 | | This source file is subject to version 3.01 of the PHP license, | 6 | | that is bundled with this package in the file LICENSE, and is | 7 | | available through the world-wide-web at the following url: | 8 | | https://www.php.net/license/3_01.txt | 9 | | If you did not receive a copy of the PHP license and are unable to | 10 | | obtain it through the world-wide-web, please send a note to | 11 | | license@php.net so we can mail you a copy immediately. | 12 | +----------------------------------------------------------------------+ 13 | | Author: Simonov Denis | 14 | +----------------------------------------------------------------------+ 15 | */ 16 | 17 | #include "pdo_firebird_utils.h" 18 | #include 19 | #include 20 | 21 | /* Returns the client version. 0 bytes are minor version, 1 bytes are major version. */ 22 | extern "C" unsigned fb_get_client_version(void) 23 | { 24 | Firebird::IMaster* master = Firebird::fb_get_master_interface(); 25 | Firebird::IUtil* util = master->getUtilInterface(); 26 | return util->getClientVersion(); 27 | } 28 | 29 | extern "C" ISC_TIME fb_encode_time(unsigned hours, unsigned minutes, unsigned seconds, unsigned fractions) 30 | { 31 | Firebird::IMaster* master = Firebird::fb_get_master_interface(); 32 | Firebird::IUtil* util = master->getUtilInterface(); 33 | return util->encodeTime(hours, minutes, seconds, fractions); 34 | } 35 | 36 | extern "C" ISC_DATE fb_encode_date(unsigned year, unsigned month, unsigned day) 37 | { 38 | Firebird::IMaster* master = Firebird::fb_get_master_interface(); 39 | Firebird::IUtil* util = master->getUtilInterface(); 40 | return util->encodeDate(year, month, day); 41 | } 42 | 43 | #if FB_API_VER >= 40 44 | static void fb_copy_status(const ISC_STATUS* from, ISC_STATUS* to, size_t maxLength) 45 | { 46 | for(size_t i=0; i < maxLength; ++i) { 47 | memcpy(to + i, from + i, sizeof(ISC_STATUS)); 48 | if (from[i] == isc_arg_end) { 49 | break; 50 | } 51 | } 52 | } 53 | 54 | /* Decodes a time with time zone into its time components. */ 55 | extern "C" void fb_decode_time_tz(const ISC_TIME_TZ* timeTz, unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned* fractions, 56 | unsigned timeZoneBufferLength, char* timeZoneBuffer) 57 | { 58 | Firebird::IMaster* master = Firebird::fb_get_master_interface(); 59 | Firebird::IUtil* util = master->getUtilInterface(); 60 | Firebird::IStatus* status = master->getStatus(); 61 | Firebird::CheckStatusWrapper st(status); 62 | util->decodeTimeTz(&st, timeTz, hours, minutes, seconds, fractions, 63 | timeZoneBufferLength, timeZoneBuffer); 64 | } 65 | 66 | /* Decodes a timestamp with time zone into its date and time components */ 67 | extern "C" void fb_decode_timestamp_tz(const ISC_TIMESTAMP_TZ* timestampTz, 68 | unsigned* year, unsigned* month, unsigned* day, 69 | unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned* fractions, 70 | unsigned timeZoneBufferLength, char* timeZoneBuffer) 71 | { 72 | Firebird::IMaster* master = Firebird::fb_get_master_interface(); 73 | Firebird::IUtil* util = master->getUtilInterface(); 74 | Firebird::IStatus* status = master->getStatus(); 75 | Firebird::CheckStatusWrapper st(status); 76 | util->decodeTimeStampTz(&st, timestampTz, year, month, day, 77 | hours, minutes, seconds, fractions, 78 | timeZoneBufferLength, timeZoneBuffer); 79 | } 80 | 81 | #endif 82 | -------------------------------------------------------------------------------- /pdo_firebird_utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | Copyright (c) The PHP Group | 4 | +----------------------------------------------------------------------+ 5 | | This source file is subject to version 3.01 of the PHP license, | 6 | | that is bundled with this package in the file LICENSE, and is | 7 | | available through the world-wide-web at the following url: | 8 | | https://www.php.net/license/3_01.txt | 9 | | If you did not receive a copy of the PHP license and are unable to | 10 | | obtain it through the world-wide-web, please send a note to | 11 | | license@php.net so we can mail you a copy immediately. | 12 | +----------------------------------------------------------------------+ 13 | | Author: Simonov Denis | 14 | +----------------------------------------------------------------------+ 15 | */ 16 | 17 | #ifndef PDO_FIREBIRD_UTILS_H 18 | #define PDO_FIREBIRD_UTILS_H 19 | 20 | #include 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | unsigned fb_get_client_version(void); 27 | 28 | ISC_TIME fb_encode_time(unsigned hours, unsigned minutes, unsigned seconds, unsigned fractions); 29 | 30 | ISC_DATE fb_encode_date(unsigned year, unsigned month, unsigned day); 31 | 32 | #if FB_API_VER >= 40 33 | 34 | void fb_decode_time_tz(const ISC_TIME_TZ* timeTz, unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned* fractions, 35 | unsigned timeZoneBufferLength, char* timeZoneBuffer); 36 | 37 | void fb_decode_timestamp_tz(const ISC_TIMESTAMP_TZ* timestampTz, 38 | unsigned* year, unsigned* month, unsigned* day, 39 | unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned* fractions, 40 | unsigned timeZoneBufferLength, char* timeZoneBuffer); 41 | 42 | #endif 43 | 44 | #ifdef __cplusplus 45 | } 46 | #endif 47 | 48 | #endif /* PDO_FIREBIRD_UTILS_H */ 49 | -------------------------------------------------------------------------------- /php_ibase_includes.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 7, 8 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 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 | | Authors: Jouni Ahto | 16 | | Andrew Avdeev | 17 | | Ard Biesheuvel | 18 | | Martin Koeditz | 19 | | others | 20 | +----------------------------------------------------------------------+ 21 | | You'll find history on Github | 22 | | https://github.com/FirebirdSQL/php-firebird/commits/master | 23 | +----------------------------------------------------------------------+ 24 | */ 25 | 26 | #ifndef PHP_IBASE_INCLUDES_H 27 | #define PHP_IBASE_INCLUDES_H 28 | 29 | #include 30 | 31 | #ifndef SQLDA_CURRENT_VERSION 32 | #define SQLDA_CURRENT_VERSION SQLDA_VERSION1 33 | #endif 34 | 35 | #ifndef METADATALENGTH 36 | #define METADATALENGTH 68 37 | #endif 38 | 39 | #define RESET_ERRMSG do { IBG(errmsg)[0] = '\0'; IBG(sql_code) = 0; } while (0) 40 | 41 | #define IB_STATUS (IBG(status)) 42 | 43 | #ifdef IBASE_DEBUG 44 | #define IBDEBUG(a) php_printf("::: %s (%s:%d)\n", a, __FILE__, __LINE__); 45 | #endif 46 | 47 | #ifndef IBDEBUG 48 | #define IBDEBUG(a) 49 | #endif 50 | 51 | extern int le_link, le_plink, le_trans; 52 | 53 | #define LE_LINK "Firebird/InterBase link" 54 | #define LE_PLINK "Firebird/InterBase persistent link" 55 | #define LE_TRANS "Firebird/InterBase transaction" 56 | 57 | #define IBASE_MSGSIZE 512 58 | #define MAX_ERRMSG (IBASE_MSGSIZE*2) 59 | 60 | #define IB_DEF_DATE_FMT "%Y-%m-%d" 61 | #define IB_DEF_TIME_FMT "%H:%M:%S" 62 | 63 | /* this value should never be > USHRT_MAX */ 64 | #define IBASE_BLOB_SEG 4096 65 | 66 | ZEND_BEGIN_MODULE_GLOBALS(ibase) 67 | ISC_STATUS status[20]; 68 | zend_resource *default_link; 69 | zend_long num_links, num_persistent; 70 | char errmsg[MAX_ERRMSG]; 71 | zend_long sql_code; 72 | zend_long default_trans_params; 73 | zend_long default_lock_timeout; // only used togetger with trans_param IBASE_LOCK_TIMEOUT 74 | ZEND_END_MODULE_GLOBALS(ibase) 75 | 76 | ZEND_EXTERN_MODULE_GLOBALS(ibase) 77 | 78 | typedef struct { 79 | isc_db_handle handle; 80 | struct tr_list *tr_list; 81 | unsigned short dialect; 82 | struct event *event_head; 83 | } ibase_db_link; 84 | 85 | typedef struct { 86 | isc_tr_handle handle; 87 | unsigned short link_cnt; 88 | unsigned long affected_rows; 89 | ibase_db_link *db_link[1]; /* last member */ 90 | } ibase_trans; 91 | 92 | typedef struct tr_list { 93 | ibase_trans *trans; 94 | struct tr_list *next; 95 | } ibase_tr_list; 96 | 97 | typedef struct { 98 | isc_blob_handle bl_handle; 99 | unsigned short type; 100 | ISC_QUAD bl_qd; 101 | } ibase_blob; 102 | 103 | typedef struct event { 104 | ibase_db_link *link; 105 | zend_resource* link_res; 106 | ISC_LONG event_id; 107 | unsigned short event_count; 108 | char **events; 109 | unsigned char *event_buffer, *result_buffer; 110 | zval callback; 111 | void *thread_ctx; 112 | struct event *event_next; 113 | enum event_state { NEW, ACTIVE, DEAD } state; 114 | } ibase_event; 115 | 116 | enum php_interbase_option { 117 | PHP_IBASE_DEFAULT = 0, 118 | PHP_IBASE_CREATE = 0, 119 | /* fetch flags */ 120 | PHP_IBASE_FETCH_BLOBS = 1, 121 | PHP_IBASE_FETCH_ARRAYS = 2, 122 | PHP_IBASE_UNIXTIME = 4, 123 | /* transaction access mode */ 124 | PHP_IBASE_WRITE = 1, 125 | PHP_IBASE_READ = 2, 126 | /* transaction isolation level */ 127 | PHP_IBASE_CONCURRENCY = 4, 128 | PHP_IBASE_COMMITTED = 8, 129 | PHP_IBASE_REC_NO_VERSION = 32, 130 | PHP_IBASE_REC_VERSION = 64, 131 | PHP_IBASE_CONSISTENCY = 16, 132 | /* transaction lock resolution */ 133 | PHP_IBASE_WAIT = 128, 134 | PHP_IBASE_NOWAIT = 256, 135 | PHP_IBASE_LOCK_TIMEOUT = 512, 136 | }; 137 | 138 | #define IBG(v) ZEND_MODULE_GLOBALS_ACCESSOR(ibase, v) 139 | 140 | #if defined(ZTS) && defined(COMPILE_DL_INTERBASE) 141 | ZEND_TSRMLS_CACHE_EXTERN() 142 | #endif 143 | 144 | #define BLOB_ID_LEN 18 145 | #define BLOB_ID_MASK "0x%" LL_MASK "x" 146 | 147 | #define BLOB_INPUT 1 148 | #define BLOB_OUTPUT 2 149 | 150 | #ifdef PHP_WIN32 151 | // Case switch, because of troubles on Windows and PHP 8.0 152 | #if PHP_VERSION_ID < 80000 153 | #define LL_MASK "I64" 154 | #else 155 | #define LL_MASK "ll" 156 | #endif 157 | #define LL_LIT(lit) lit ## I64 158 | typedef void (__stdcall *info_func_t)(char*); 159 | #else 160 | #define LL_MASK "ll" 161 | #define LL_LIT(lit) lit ## ll 162 | typedef void (*info_func_t)(char*); 163 | #endif 164 | 165 | void _php_ibase_error(void); 166 | void _php_ibase_module_error(char *, ...) 167 | PHP_ATTRIBUTE_FORMAT(printf,1,2); 168 | 169 | /* determine if a resource is a link or transaction handle */ 170 | #define PHP_IBASE_LINK_TRANS(zv, lh, th) \ 171 | do { \ 172 | if (!zv) { \ 173 | lh = (ibase_db_link *)zend_fetch_resource2( \ 174 | IBG(default_link), "InterBase link", le_link, le_plink); \ 175 | } else { \ 176 | _php_ibase_get_link_trans(INTERNAL_FUNCTION_PARAM_PASSTHRU, zv, &lh, &th); \ 177 | } \ 178 | if (SUCCESS != _php_ibase_def_trans(lh, &th)) { RETURN_FALSE; } \ 179 | } while (0) 180 | 181 | int _php_ibase_def_trans(ibase_db_link *ib_link, ibase_trans **trans); 182 | void _php_ibase_get_link_trans(INTERNAL_FUNCTION_PARAMETERS, zval *link_id, 183 | ibase_db_link **ib_link, ibase_trans **trans); 184 | 185 | /* provided by ibase_query.c */ 186 | void php_ibase_query_minit(INIT_FUNC_ARGS); 187 | 188 | /* provided by ibase_blobs.c */ 189 | void php_ibase_blobs_minit(INIT_FUNC_ARGS); 190 | int _php_ibase_string_to_quad(char const *id, ISC_QUAD *qd); 191 | zend_string *_php_ibase_quad_to_string(ISC_QUAD const qd); 192 | int _php_ibase_blob_get(zval *return_value, ibase_blob *ib_blob, zend_ulong max_len); 193 | int _php_ibase_blob_add(zval *string_arg, ibase_blob *ib_blob); 194 | 195 | /* provided by ibase_events.c */ 196 | void php_ibase_events_minit(INIT_FUNC_ARGS); 197 | void _php_ibase_free_event(ibase_event *event); 198 | 199 | /* provided by ibase_service.c */ 200 | void php_ibase_service_minit(INIT_FUNC_ARGS); 201 | 202 | #ifndef max 203 | #define max(a,b) ((a)>(b)?(a):(b)) 204 | #endif 205 | 206 | #endif /* PHP_IBASE_INCLUDES_H */ 207 | -------------------------------------------------------------------------------- /php_ibase_udf.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 7, 8 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 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 | | Authors: Jouni Ahto | 16 | | Andrew Avdeev | 17 | | Ard Biesheuvel | 18 | | Martin Koeditz | 19 | | others | 20 | +----------------------------------------------------------------------+ 21 | | You'll find history on Github | 22 | | https://github.com/FirebirdSQL/php-firebird/commits/master | 23 | +----------------------------------------------------------------------+ 24 | */ 25 | 26 | /** 27 | * This UDF library adds the ability to call PHP functions from SQL 28 | * statements. Because of SQL's strong typing, you will have to declare 29 | * an external function for every combination { output type, #args } that 30 | * your application requires. 31 | * 32 | * Declare the functions like this: 33 | * 34 | * DECLARE EXTERNAL FUNCTION CALL_PHP1 35 | * CSTRING(xx), 36 | * BY DESCRIPTOR, 37 | * INTEGER BY DESCRIPTOR 38 | * RETURNS PARAMETER 2 39 | * ENTRY_POINT 'udf_call_php1' MODULE_NAME 'php_ibase_udf' 40 | * 41 | * DECLARE EXTERNAL FUNCTION CALL_PHP2 42 | * CSTRING(xx), 43 | * BY DESCRIPTOR, 44 | * INTEGER BY DESCRIPTOR, 45 | * INTEGER BY DESCRIPTOR 46 | * RETURNS PARAMETER 2 47 | * ENTRY_POINT 'udf_call_php2' MODULE_NAME 'php_ibase_udf' 48 | * 49 | * ... and so on. [for up to 8 input arguments] 50 | * 51 | * The first input parameter contains the name of the PHP function you want 52 | * to call. The second argument is the result. (omit this argument when calling 53 | * the function) The return type of the function is the declared type of the 54 | * result. The value returned from the PHP function being called will 55 | * automatically be converted if necessary. 56 | * The arguments should have their types declared as well, but you're free 57 | * to pass arguments of other types instead. They will be converted to the 58 | * best matching PHP type before being passed to the PHP function. 59 | * 60 | * The declared functions can be called from SQL like: 61 | * 62 | * SELECT * FROM WHERE CALL_PHP1('soundex',) NOT LIKE ? 63 | * or 64 | * UPDATE
SET = CALL_PHP1('ucwords',) 65 | * 66 | * Additionally, there's a function 'exec_php' which allows the contents 67 | * of text BLOB fields to be parsed and executed by PHP. This is most useful 68 | * for declaring functions that can then be called with CALL_PHPx. 69 | * 70 | * DECLARE EXTERNAL FUNCTION EXEC_PHP 71 | * BLOB, 72 | * INTEGER BY DESCRIPTOR, 73 | * SMALLINT 74 | * RETURNS PARAMETER 2 75 | * ENTRY_POINT 'exec_php' MODULE_NAME 'php_ibase_udf' 76 | * 77 | * The function will return 1 if execution succeeded and 0 if an error 78 | * occurred. The result that is returned from the executed PHP code is 79 | * ignored. You can pass a non-zero value as second argument to force 80 | * the embedded PHP engine to re-initialise. 81 | * 82 | * There are several ways to build this library, depending on which way the 83 | * database is accessed. If you're using the classic server on a local 84 | * connection, you should compile the library like this: 85 | * 86 | * gcc -shared `php-config --includes` `php-config --ldflags` \ 87 | * `php-config --libs` -o php_ibase_udf.so php_ibase_udf.c 88 | * 89 | * If you connect to the classic server by TCP/IP, you should build the 90 | * PHP embedded static library and link against that. 91 | * 92 | * gcc -shared `php-config --includes` `php-config --ldflags` \ 93 | * `php-config --libs` -o php_ibase_udf.so php_ibase_udf.c \ 94 | * /usr/lib/libphp7.a 95 | * 96 | * If you use the super server, you should also link against the embedded 97 | * library, but be sure to enable thread safety, as the super server is 98 | * multi-threaded. After building, copy the resulting file to the folder 99 | * where your database expects to find its UDFs. 100 | */ 101 | 102 | #include "zend.h" 103 | #include "zend_API.h" 104 | 105 | #include "php.h" 106 | #include "php_ini.h" 107 | 108 | #include "ibase.h" 109 | 110 | #define min(a,b) ((a)<(b)?(a):(b)) 111 | 112 | #ifdef PHP_WIN32 113 | #define LL_LIT(lit) lit ## I64 114 | #else 115 | #define LL_LIT(lit) lit ## ll 116 | #endif 117 | 118 | #ifdef ZTS 119 | # include 120 | 121 | static void ***tsrm_ls; 122 | pthread_mutex_t mtx_res = PTHREAD_MUTEX_INITIALIZER; 123 | 124 | #define LOCK() do { pthread_mutex_lock(&mtx_res); } while (0) 125 | #define UNLOCK() do { pthread_mutex_unlock(&mtx_res); } while (0) 126 | #else 127 | #define LOCK() 128 | #define UNLOCK() 129 | #endif 130 | 131 | #ifdef PHP_EMBED 132 | # include "php_main.h" 133 | # include "sapi/embed/php_embed.h" 134 | 135 | static void __attribute__((constructor)) init() 136 | { 137 | php_embed_init(0, NULL P); 138 | } 139 | 140 | static void __attribute__((destructor)) fini() 141 | { 142 | php_embed_shutdown(); 143 | } 144 | 145 | #endif 146 | 147 | /** 148 | * Gets the contents of the BLOB b and offers it to Zend for parsing/execution 149 | */ 150 | void exec_php(BLOBCALLBACK b, PARAMDSC *res, ISC_SHORT *init) 151 | { 152 | int result, remaining = b->blob_total_length, i = 0; 153 | char *code = pemalloc(remaining+1, 1); 154 | ISC_USHORT read; 155 | 156 | for (code[remaining] = '\0'; remaining > 0; remaining -= read) 157 | b->blob_get_segment(b->blob_handle, &code[i++<<16],min(0x10000,remaining), &read); 158 | 159 | LOCK(); 160 | 161 | switch (init && *init) { 162 | 163 | default: 164 | #ifdef PHP_EMBED 165 | php_request_shutdown(NULL); 166 | if (FAILURE == (result = php_request_startup())) { 167 | break; 168 | } 169 | case 0: 170 | #endif 171 | /* feed it to the parser */ 172 | zend_first_try { 173 | result = zend_eval_stringl(code, b->blob_total_length, NULL, "Firebird Embedded PHP engine"); 174 | } zend_end_try(); 175 | } 176 | 177 | UNLOCK(); 178 | 179 | free(code); 180 | 181 | res->dsc_dtype = dtype_long; 182 | *(ISC_LONG*)res->dsc_address = (result == SUCCESS); 183 | } 184 | 185 | static ISC_INT64 const scales[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 100000000, 1000000000, 186 | 1000000000, LL_LIT(10000000000),LL_LIT(100000000000),LL_LIT(10000000000000),LL_LIT(100000000000000), 187 | LL_LIT(1000000000000000),LL_LIT(1000000000000000),LL_LIT(1000000000000000000) }; 188 | 189 | 190 | static void call_php(char *name, PARAMDSC *r, int argc, PARAMDSC **argv) 191 | { 192 | do { 193 | zval callback, args[4], return_value; 194 | PARAMVARY *res = (PARAMVARY*)r->dsc_address; 195 | int i; 196 | 197 | ZVAL_STRING(&callback, name); 198 | 199 | LOCK(); 200 | 201 | /* check if the requested function exists */ 202 | if (!zend_is_callable(&callback, 0, NULL)) { 203 | break; 204 | } 205 | 206 | UNLOCK(); 207 | 208 | /* create the argument array */ 209 | for (i = 0; i < argc; ++i) { 210 | 211 | /* test arg for null */ 212 | if (argv[i]->dsc_flags & DSC_null) { 213 | ZVAL_NULL(&args[i]); 214 | continue; 215 | } 216 | 217 | switch (argv[i]->dsc_dtype) { 218 | ISC_INT64 l; 219 | struct tm t; 220 | char const *fmt; 221 | char d[64]; 222 | 223 | case dtype_cstring: 224 | //??? 225 | ZVAL_STRING(&args[i], (char*)argv[i]->dsc_address); 226 | break; 227 | 228 | case dtype_text: 229 | //??? 230 | ZVAL_STRINGL(&args[i], (char*)argv[i]->dsc_address, argv[i]->dsc_length); 231 | break; 232 | 233 | case dtype_varying: 234 | //??? 235 | ZVAL_STRINGL(&args[i], ((PARAMVARY*)argv[i]->dsc_address)->vary_string, 236 | ((PARAMVARY*)argv[i]->dsc_address)->vary_length); 237 | break; 238 | 239 | case dtype_short: 240 | if (argv[i]->dsc_scale == 0) { 241 | ZVAL_LONG(&args[i], *(short*)argv[i]->dsc_address); 242 | } else { 243 | ZVAL_DOUBLE(&args[i], 244 | ((double)*(short*)argv[i]->dsc_address)/scales[-argv[i]->dsc_scale]); 245 | } 246 | break; 247 | 248 | case dtype_long: 249 | if (argv[i]->dsc_scale == 0) { 250 | ZVAL_LONG(&args[i], *(ISC_LONG*)argv[i]->dsc_address); 251 | } else { 252 | ZVAL_DOUBLE(&args[i], 253 | ((double)*(ISC_LONG*)argv[i]->dsc_address)/scales[-argv[i]->dsc_scale]); 254 | } 255 | break; 256 | 257 | case dtype_int64: 258 | l = *(ISC_INT64*)argv[i]->dsc_address; 259 | 260 | if (argv[i]->dsc_scale == 0 && l <= ZEND_LONG_MAX && l >= ZEND_LONG_MIN) { 261 | ZVAL_LONG(&args[i], (zend_long)l); 262 | } else { 263 | ZVAL_DOUBLE(&args[i], ((double)l)/scales[-argv[i]->dsc_scale]); 264 | } 265 | break; 266 | 267 | case dtype_real: 268 | ZVAL_DOUBLE(&args[i], *(float*)argv[i]->dsc_address); 269 | break; 270 | 271 | case dtype_double: 272 | ZVAL_DOUBLE(&args[i], *(double*)argv[i]->dsc_address); 273 | break; 274 | 275 | case dtype_sql_date: 276 | isc_decode_sql_date((ISC_DATE*)argv[i]->dsc_address, &t); 277 | ZVAL_STRINGL(&args[i], d, strftime(d, sizeof(d), INI_STR("ibase.dateformat"), &t),1); 278 | break; 279 | 280 | case dtype_sql_time: 281 | isc_decode_sql_time((ISC_TIME*)argv[i]->dsc_address, &t); 282 | ZVAL_STRINGL(&args[i], d, strftime(d, sizeof(d), INI_STR("ibase.timeformat"), &t),1); 283 | break; 284 | 285 | case dtype_timestamp: 286 | isc_decode_timestamp((ISC_TIMESTAMP*)argv[i]->dsc_address, &t); 287 | ZVAL_STRINGL(&args[i], d, strftime(d, sizeof(d), INI_STR("ibase.timestampformat"), &t)); 288 | break; 289 | } 290 | } 291 | 292 | LOCK(); 293 | 294 | /* now call the function */ 295 | if (FAILURE == call_user_function(NULL, NULL, 296 | &callback, &return_value, argc, args)) { 297 | UNLOCK(); 298 | break; 299 | } 300 | 301 | UNLOCK(); 302 | 303 | for (i = 0; i < argc; ++i) { 304 | switch (argv[i]->dsc_dtype) { 305 | case dtype_sql_date: 306 | case dtype_sql_time: 307 | case dtype_timestamp: 308 | zval_ptr_dtor_nogc(&args[i]); 309 | } 310 | } 311 | 312 | zval_ptr_dtor_str(&callback); 313 | 314 | /* return whatever type we got back from the callback: let DB handle conversion */ 315 | switch (Z_TYPE(return_value)) { 316 | 317 | case IS_LONG: 318 | r->dsc_dtype = dtype_long; 319 | *(zend_long*)r->dsc_address = Z_LVAL(return_value); 320 | r->dsc_length = sizeof(zend_long); 321 | break; 322 | 323 | case IS_DOUBLE: 324 | r->dsc_dtype = dtype_double; 325 | *(double*)r->dsc_address = Z_DVAL(return_value); 326 | r->dsc_length = sizeof(double); 327 | break; 328 | 329 | case IS_NULL: 330 | r->dsc_flags |= DSC_null; 331 | break; 332 | 333 | default: 334 | convert_to_string(&return_value); 335 | 336 | case IS_STRING: 337 | r->dsc_dtype = dtype_varying; 338 | memcpy(res->vary_string, Z_STRVAL(return_value), 339 | (res->vary_length = min(r->dsc_length-2,Z_STRLEN(return_value)))); 340 | r->dsc_length = res->vary_length+2; 341 | break; 342 | } 343 | 344 | zval_ptr_dtor(&return_value); 345 | 346 | return; 347 | 348 | } while (0); 349 | 350 | /** 351 | * If we end up here, we should report an error back to the DB engine, but 352 | * that's not possible. We can however report it back to PHP. 353 | */ 354 | LOCK(); 355 | php_error_docref(NULL, E_WARNING, "Error calling function '%s' from database", name); 356 | UNLOCK(); 357 | } 358 | 359 | 360 | /* Entry points for the DB engine */ 361 | 362 | void udf_call_php1(char *name, PARAMDSC *r, PARAMDSC *arg1) 363 | { 364 | PARAMDSC *args[1] = { arg1 }; 365 | call_php(name, r, 1, args); 366 | } 367 | 368 | void udf_call_php2(char *name, PARAMDSC *r, PARAMDSC *arg1, PARAMDSC *arg2) 369 | { 370 | PARAMDSC *args[2] = { arg1, arg2 }; 371 | call_php(name, r, 2, args); 372 | } 373 | 374 | void udf_call_php3(char *name, PARAMDSC *r, PARAMDSC *arg1, PARAMDSC *arg2, PARAMDSC *arg3) 375 | { 376 | PARAMDSC *args[3] = { arg1, arg2, arg3 }; 377 | call_php(name, r, 3, args); 378 | } 379 | 380 | void udf_call_php4(char *name, PARAMDSC *r, PARAMDSC *arg1, PARAMDSC *arg2, PARAMDSC *arg3, 381 | PARAMDSC *arg4) 382 | { 383 | PARAMDSC *args[4] = { arg1, arg2, arg3, arg4 }; 384 | call_php(name, r, 4, args); 385 | } 386 | 387 | void udf_call_php5(char *name, PARAMDSC *r, PARAMDSC *arg1, PARAMDSC *arg2, PARAMDSC *arg3, 388 | PARAMDSC *arg4, PARAMDSC *arg5) 389 | { 390 | PARAMDSC *args[5] = { arg1, arg2, arg3, arg4, arg5 }; 391 | call_php(name, r, 5, args); 392 | } 393 | 394 | void udf_call_php6(char *name, PARAMDSC *r, PARAMDSC *arg1, PARAMDSC *arg2, PARAMDSC *arg3, 395 | PARAMDSC *arg4, PARAMDSC *arg5, PARAMDSC *arg6) 396 | { 397 | PARAMDSC *args[6] = { arg1, arg2, arg3, arg4, arg5, arg6 }; 398 | call_php(name, r, 6, args); 399 | } 400 | 401 | void udf_call_php7(char *name, PARAMDSC *r, PARAMDSC *arg1, PARAMDSC *arg2, PARAMDSC *arg3, 402 | PARAMDSC *arg4, PARAMDSC *arg5, PARAMDSC *arg6, PARAMDSC *arg7) 403 | { 404 | PARAMDSC *args[7] = { arg1, arg2, arg3, arg4, arg5, arg6, arg7 }; 405 | call_php(name, r, 7, args); 406 | } 407 | 408 | void udf_call_php8(char *name, PARAMDSC *r, PARAMDSC *arg1, PARAMDSC *arg2, PARAMDSC *arg3, 409 | PARAMDSC *arg4, PARAMDSC *arg5, PARAMDSC *arg6, PARAMDSC *arg7, PARAMDSC *arg8) 410 | { 411 | PARAMDSC *args[8] = { arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 }; 412 | call_php(name, r, 8, args); 413 | } 414 | -------------------------------------------------------------------------------- /php_interbase.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 7, 8 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 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 | | Authors: Jouni Ahto | 16 | | Andrew Avdeev | 17 | | Ard Biesheuvel | 18 | | Martin Koeditz | 19 | | Jonatan Klemets | 20 | | others | 21 | +----------------------------------------------------------------------+ 22 | | You'll find history on Github | 23 | | https://github.com/FirebirdSQL/php-firebird/commits/master | 24 | +----------------------------------------------------------------------+ 25 | */ 26 | 27 | #ifndef PHP_INTERBASE_H 28 | #define PHP_INTERBASE_H 29 | 30 | extern zend_module_entry ibase_module_entry; 31 | #define phpext_interbase_ptr &ibase_module_entry 32 | 33 | #include "php_version.h" 34 | // Keep version in track with Firebird 35 | #define PHP_INTERBASE_VERSION "5.0.2" 36 | 37 | PHP_MINIT_FUNCTION(ibase); 38 | PHP_RINIT_FUNCTION(ibase); 39 | PHP_MSHUTDOWN_FUNCTION(ibase); 40 | PHP_RSHUTDOWN_FUNCTION(ibase); 41 | PHP_MINFO_FUNCTION(ibase); 42 | 43 | PHP_FUNCTION(ibase_connect); 44 | PHP_FUNCTION(ibase_pconnect); 45 | PHP_FUNCTION(ibase_close); 46 | PHP_FUNCTION(ibase_drop_db); 47 | PHP_FUNCTION(ibase_query); 48 | PHP_FUNCTION(ibase_fetch_row); 49 | PHP_FUNCTION(ibase_fetch_assoc); 50 | PHP_FUNCTION(ibase_fetch_object); 51 | PHP_FUNCTION(ibase_free_result); 52 | PHP_FUNCTION(ibase_name_result); 53 | PHP_FUNCTION(ibase_prepare); 54 | PHP_FUNCTION(ibase_execute); 55 | PHP_FUNCTION(ibase_free_query); 56 | 57 | PHP_FUNCTION(ibase_timefmt); 58 | 59 | PHP_FUNCTION(ibase_gen_id); 60 | PHP_FUNCTION(ibase_num_fields); 61 | PHP_FUNCTION(ibase_num_params); 62 | #if abies_0 63 | PHP_FUNCTION(ibase_num_rows); 64 | #endif 65 | PHP_FUNCTION(ibase_affected_rows); 66 | PHP_FUNCTION(ibase_field_info); 67 | PHP_FUNCTION(ibase_param_info); 68 | 69 | PHP_FUNCTION(ibase_trans); 70 | PHP_FUNCTION(ibase_commit); 71 | PHP_FUNCTION(ibase_rollback); 72 | PHP_FUNCTION(ibase_commit_ret); 73 | PHP_FUNCTION(ibase_rollback_ret); 74 | 75 | PHP_FUNCTION(ibase_blob_create); 76 | PHP_FUNCTION(ibase_blob_add); 77 | PHP_FUNCTION(ibase_blob_cancel); 78 | PHP_FUNCTION(ibase_blob_open); 79 | PHP_FUNCTION(ibase_blob_get); 80 | PHP_FUNCTION(ibase_blob_close); 81 | PHP_FUNCTION(ibase_blob_echo); 82 | PHP_FUNCTION(ibase_blob_info); 83 | PHP_FUNCTION(ibase_blob_import); 84 | 85 | PHP_FUNCTION(ibase_add_user); 86 | PHP_FUNCTION(ibase_modify_user); 87 | PHP_FUNCTION(ibase_delete_user); 88 | 89 | PHP_FUNCTION(ibase_service_attach); 90 | PHP_FUNCTION(ibase_service_detach); 91 | PHP_FUNCTION(ibase_backup); 92 | PHP_FUNCTION(ibase_restore); 93 | PHP_FUNCTION(ibase_maintain_db); 94 | PHP_FUNCTION(ibase_db_info); 95 | PHP_FUNCTION(ibase_server_info); 96 | 97 | PHP_FUNCTION(ibase_errmsg); 98 | PHP_FUNCTION(ibase_errcode); 99 | 100 | PHP_FUNCTION(ibase_wait_event); 101 | PHP_FUNCTION(ibase_set_event_handler); 102 | PHP_FUNCTION(ibase_free_event_handler); 103 | 104 | #else 105 | 106 | #define phpext_interbase_ptr NULL 107 | 108 | #endif /* PHP_INTERBASE_H */ 109 | -------------------------------------------------------------------------------- /tests/002.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | InterBase: connect, close and pconnect 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 27 | --EXPECT-- 28 | --- test1 --- 29 | 1 test table not created with isql 30 | --- 31 | --- test1 --- 32 | 1 test table not created with isql 33 | --- 34 | -------------------------------------------------------------------------------- /tests/003.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | InterBase: misc sql types (may take a while) 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | V_CHAR,0,strlen($v_char)) != $v_char){ 70 | echo " CHAR fail:\n"; 71 | echo " in: $v_char\n"; 72 | echo " out: $row->V_CHAR\n"; 73 | } 74 | if($row->V_DATE != $v_date){ 75 | echo " DATE fail\n"; 76 | echo " in: $v_date\n"; 77 | echo " out: $row->V_DATE\n"; 78 | } 79 | if($row->V_DECIMAL4_2 != $v_decimal4_2){ 80 | echo " DECIMAL4_2 fail\n"; 81 | echo " in: $v_decimal4_2\n"; 82 | echo " out: $row->V_DECIMAL4_2\n"; 83 | } 84 | if($row->V_DECIMAL4_0 != $v_decimal4_0){ 85 | echo " DECIMAL4_0 fail\n"; 86 | echo " in: $v_decimal4_0\n"; 87 | echo " out: $row->V_DECIMAL4_0\n"; 88 | } 89 | if($row->V_DECIMAL7_2 != $v_decimal7_2){ 90 | echo " DECIMAL7_2 fail\n"; 91 | echo " in: $v_decimal7_2\n"; 92 | echo " out: $row->V_DECIMAL7_2\n"; 93 | } 94 | if($row->V_DECIMAL7_0 != $v_decimal7_0){ 95 | echo " DECIMAL7_0 fail\n"; 96 | echo " in: $v_decimal7_0\n"; 97 | echo " out: $row->V_DECIMAL7_0\n"; 98 | } 99 | if($row->V_NUMERIC15_15 != $v_numeric15_15){ 100 | echo " NUMERIC15_15 fail\n"; 101 | echo " in: $v_numeric15_15\n"; 102 | echo " out: $row->V_NUMERIC15_15\n"; 103 | } 104 | if($row->V_DECIMAL18_3 != $v_decimal18_3){ 105 | echo " DECIMAL18_3 fail\n"; 106 | echo " in: $v_decimal18_3\n"; 107 | echo " out: $row->V_DECIMAL18_3\n"; 108 | } 109 | if($row->V_NUMERIC15_0 != (string)$v_numeric15_0){ 110 | echo " NUMERIC15_0 fail\n"; 111 | echo " in: $v_numeric15_0\n"; 112 | echo " out: $row->V_NUMERIC15_0\n"; 113 | } 114 | 115 | if(abs($row->V_DOUBLE - $v_double) > abs($v_double / 1E15)){ 116 | echo " DOUBLE fail\n"; 117 | echo " in: $v_double\n"; 118 | echo " out: $row->V_DOUBLE\n"; 119 | } 120 | if(abs($row->V_FLOAT - $v_float) > abs($v_float / 1E7)){ 121 | echo " FLOAT fail\n"; 122 | echo " in: $v_float\n"; 123 | echo " out: $row->V_FLOAT\n"; 124 | } 125 | if($row->V_INTEGER != $v_integer){ 126 | echo " INTEGER fail\n"; 127 | echo " in: $v_integer\n"; 128 | echo " out: $row->V_INTEGER\n"; 129 | } 130 | if($row->V_SMALLINT != $v_smallint){ 131 | echo " SMALLINT fail\n"; 132 | echo " in: $v_smallint\n"; 133 | echo " out: $row->V_SMALLINT\n"; 134 | } 135 | 136 | if(substr($row->V_VARCHAR,0,strlen($v_varchar)) != $v_varchar){ 137 | echo " VARCHAR fail:\n"; 138 | echo " in: $v_varchar\n"; 139 | echo " out: $row->V_VARCHAR\n"; 140 | } 141 | 142 | ibase_free_result($sel); 143 | } /* for($iter) */ 144 | 145 | /* check for correct handling of duplicate field names */ 146 | $q = ibase_query('SELECT 1 AS id, 2 AS id, 3 AS id, 4 AS id, 5 AS id, 6 AS id, 7 AS id, 8 AS id, 9 AS id, 147 | 10 AS id, 11 AS id, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 FROM rdb$database'); 148 | var_dump(ibase_fetch_assoc($q)); 149 | 150 | ibase_close(); 151 | echo "end of test\n"; 152 | ?> 153 | --EXPECT-- 154 | array(22) { 155 | ["ID"]=> 156 | int(1) 157 | ["ID_01"]=> 158 | int(2) 159 | ["ID_02"]=> 160 | int(3) 161 | ["ID_03"]=> 162 | int(4) 163 | ["ID_04"]=> 164 | int(5) 165 | ["ID_05"]=> 166 | int(6) 167 | ["ID_06"]=> 168 | int(7) 169 | ["ID_07"]=> 170 | int(8) 171 | ["ID_08"]=> 172 | int(9) 173 | ["ID_09"]=> 174 | int(10) 175 | ["ID_10"]=> 176 | int(11) 177 | ["CONSTANT"]=> 178 | int(12) 179 | ["CONSTANT_01"]=> 180 | int(13) 181 | ["CONSTANT_02"]=> 182 | int(14) 183 | ["CONSTANT_03"]=> 184 | int(15) 185 | ["CONSTANT_04"]=> 186 | int(16) 187 | ["CONSTANT_05"]=> 188 | int(17) 189 | ["CONSTANT_06"]=> 190 | int(18) 191 | ["CONSTANT_07"]=> 192 | int(19) 193 | ["CONSTANT_08"]=> 194 | int(20) 195 | ["CONSTANT_09"]=> 196 | int(21) 197 | ["CONSTANT_10"]=> 198 | int(22) 199 | } 200 | end of test 201 | -------------------------------------------------------------------------------- /tests/004.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | InterBase: BLOB test 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | V_BLOB); 40 | 41 | $blob = ''; 42 | while($piece = ibase_blob_get($bl_h, 1 + rand() % 1024)) 43 | $blob .= $piece; 44 | if($blob != $blob_str) 45 | echo " BLOB 1 fail (1)\n"; 46 | ibase_blob_close($bl_h); 47 | 48 | $bl_h = ibase_blob_open($link,$row->V_BLOB); 49 | 50 | $blob = ''; 51 | while($piece = ibase_blob_get($bl_h, 100 * 1024)) 52 | $blob .= $piece; 53 | if($blob != $blob_str) 54 | echo " BLOB 1 fail (2)\n"; 55 | ibase_blob_close($bl_h); 56 | ibase_free_result($q); 57 | unset($blob); 58 | 59 | echo "create blob 2\n"; 60 | 61 | ibase_query("INSERT INTO test4 (v_integer, v_blob) VALUES (2, ?)", $blob_str); 62 | 63 | echo "test blob 2\n"; 64 | 65 | $q = ibase_query("SELECT v_blob FROM test4 WHERE v_integer = 2"); 66 | $row = ibase_fetch_object($q,IBASE_TEXT); 67 | 68 | if($row->V_BLOB != $blob_str) 69 | echo " BLOB 2 fail\n"; 70 | ibase_free_result($q); 71 | unset($blob); 72 | 73 | 74 | echo "create blob 3\n"; 75 | 76 | $bl_h = ibase_blob_create($link); 77 | 78 | ibase_blob_add($bl_h, "+----------------------------------------------------------------------+\n"); 79 | ibase_blob_add($bl_h, "| PHP HTML Embedded Scripting Language Version 3.0 |\n"); 80 | ibase_blob_add($bl_h, "+----------------------------------------------------------------------+\n"); 81 | ibase_blob_add($bl_h, "| Copyright (c) 1997-2000 PHP Development Team (See Credits file) |\n"); 82 | ibase_blob_add($bl_h, "+----------------------------------------------------------------------+\n"); 83 | ibase_blob_add($bl_h, "| This program is free software; you can redistribute it and/or modify |\n"); 84 | ibase_blob_add($bl_h, "| it under the terms of one of the following licenses: |\n"); 85 | ibase_blob_add($bl_h, "| |\n"); 86 | ibase_blob_add($bl_h, "| A) the GNU General Public License as published by the Free Software |\n"); 87 | ibase_blob_add($bl_h, "| Foundation; either version 2 of the License, or (at your option) |\n"); 88 | ibase_blob_add($bl_h, "| any later version. |\n"); 89 | ibase_blob_add($bl_h, "| |\n"); 90 | ibase_blob_add($bl_h, "| B) the PHP License as published by the PHP Development Team and |\n"); 91 | ibase_blob_add($bl_h, "| included in the distribution in the file: LICENSE |\n"); 92 | ibase_blob_add($bl_h, "| |\n"); 93 | ibase_blob_add($bl_h, "| This program is distributed in the hope that it will be useful, |\n"); 94 | ibase_blob_add($bl_h, "| but WITHOUT ANY WARRANTY; without even the implied warranty of |\n"); 95 | ibase_blob_add($bl_h, "| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |\n"); 96 | ibase_blob_add($bl_h, "| GNU General Public License for more details. |\n"); 97 | ibase_blob_add($bl_h, "| |\n"); 98 | ibase_blob_add($bl_h, "| You should have received a copy of both licenses referred to here. |\n"); 99 | ibase_blob_add($bl_h, "| If you did not, or have any questions about PHP licensing, please |\n"); 100 | ibase_blob_add($bl_h, "| contact core@php.net. |\n"); 101 | ibase_blob_add($bl_h, "+----------------------------------------------------------------------+\n"); 102 | $bl_s = ibase_blob_close($bl_h); 103 | ibase_query("INSERT INTO test4 (v_integer, v_blob) VALUES (3, ?)", $bl_s); 104 | ibase_commit(); 105 | echo "echo blob 3\n"; 106 | 107 | $q = ibase_query("SELECT v_blob FROM test4 WHERE v_integer = 3"); 108 | $row = ibase_fetch_object($q); 109 | ibase_commit(); 110 | ibase_close(); 111 | 112 | $link = ibase_connect($test_base); 113 | ibase_blob_echo($link, $row->V_BLOB); 114 | ibase_free_result($q); 115 | 116 | echo "fetch blob 3\n"; 117 | $q = ibase_query("SELECT v_blob FROM test4 WHERE v_integer = 3"); 118 | $row = ibase_fetch_object($q,IBASE_TEXT); 119 | echo $row->V_BLOB; 120 | ibase_free_result($q); 121 | 122 | ibase_close(); 123 | unlink($name); 124 | echo "end of test\n"; 125 | ?> 126 | --EXPECT-- 127 | import blob 1 128 | test blob 1 129 | create blob 2 130 | test blob 2 131 | create blob 3 132 | echo blob 3 133 | +----------------------------------------------------------------------+ 134 | | PHP HTML Embedded Scripting Language Version 3.0 | 135 | +----------------------------------------------------------------------+ 136 | | Copyright (c) 1997-2000 PHP Development Team (See Credits file) | 137 | +----------------------------------------------------------------------+ 138 | | This program is free software; you can redistribute it and/or modify | 139 | | it under the terms of one of the following licenses: | 140 | | | 141 | | A) the GNU General Public License as published by the Free Software | 142 | | Foundation; either version 2 of the License, or (at your option) | 143 | | any later version. | 144 | | | 145 | | B) the PHP License as published by the PHP Development Team and | 146 | | included in the distribution in the file: LICENSE | 147 | | | 148 | | This program is distributed in the hope that it will be useful, | 149 | | but WITHOUT ANY WARRANTY; without even the implied warranty of | 150 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 151 | | GNU General Public License for more details. | 152 | | | 153 | | You should have received a copy of both licenses referred to here. | 154 | | If you did not, or have any questions about PHP licensing, please | 155 | | contact core@php.net. | 156 | +----------------------------------------------------------------------+ 157 | fetch blob 3 158 | +----------------------------------------------------------------------+ 159 | | PHP HTML Embedded Scripting Language Version 3.0 | 160 | +----------------------------------------------------------------------+ 161 | | Copyright (c) 1997-2000 PHP Development Team (See Credits file) | 162 | +----------------------------------------------------------------------+ 163 | | This program is free software; you can redistribute it and/or modify | 164 | | it under the terms of one of the following licenses: | 165 | | | 166 | | A) the GNU General Public License as published by the Free Software | 167 | | Foundation; either version 2 of the License, or (at your option) | 168 | | any later version. | 169 | | | 170 | | B) the PHP License as published by the PHP Development Team and | 171 | | included in the distribution in the file: LICENSE | 172 | | | 173 | | This program is distributed in the hope that it will be useful, | 174 | | but WITHOUT ANY WARRANTY; without even the implied warranty of | 175 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 176 | | GNU General Public License for more details. | 177 | | | 178 | | You should have received a copy of both licenses referred to here. | 179 | | If you did not, or have any questions about PHP licensing, please | 180 | | contact core@php.net. | 181 | +----------------------------------------------------------------------+ 182 | end of test 183 | -------------------------------------------------------------------------------- /tests/005.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | InterBase: transactions 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 210 | --EXPECTF-- 211 | default transaction: 212 | empty table 213 | --- test5 --- 214 | --- 215 | one row 216 | --- test5 --- 217 | 1 218 | --- 219 | after rollback table empty again 220 | --- test5 --- 221 | --- 222 | one row 223 | --- test5 --- 224 | 2 225 | --- 226 | one row 227 | --- test5 --- 228 | 2 229 | --- 230 | one row... again. 231 | --- test5 --- 232 | 2 233 | --- 234 | one row. 235 | --- test5 --- 236 | 2 237 | --- 238 | one row 239 | --- test5 --- 240 | 2 241 | --- 242 | two rows 243 | --- test5 --- 244 | 2 245 | 3 246 | --- 247 | two rows again 248 | --- test5 --- 249 | 2 250 | 4 251 | --- 252 | one row in second transaction 253 | --- test5 --- 254 | 2 255 | --- 256 | three rows in third transaction 257 | --- test5 --- 258 | 2 259 | 3 260 | 4 261 | --- 262 | three rows in fourth transaction with deadlock 263 | --- test5 --- 264 | 2 265 | 3 266 | 4 267 | errmsg [lock conflict on no wait transaction deadlock %a] 268 | --- 269 | three rows 270 | --- test5 --- 271 | 2 272 | 3 273 | 4 274 | --- 275 | four rows 276 | --- test5 --- 277 | 2 278 | 3 279 | 4 280 | 5 281 | --- 282 | four rows again 283 | --- test5 --- 284 | 2 285 | 3 286 | 4 287 | 5 288 | --- 289 | end of test 290 | -------------------------------------------------------------------------------- /tests/006.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | InterBase: binding (may take a while) 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | V_CHAR,0,strlen($v_char)) != $v_char) { 61 | echo " CHAR fail:\n"; 62 | echo " in: $v_char\n"; 63 | echo " out: $row->V_CHAR\n"; 64 | } 65 | if($row->V_DATE != $v_date) { 66 | echo " DATE fail\n"; 67 | echo " in: $v_date\n"; 68 | echo " out: $row->V_DATE\n"; 69 | } 70 | if($row->V_DECIMAL != $v_decimal) { 71 | echo " DECIMAL fail\n"; 72 | echo " in: $v_decimal\n"; 73 | echo " out: $row->V_DECIMAL\n"; 74 | } 75 | if(abs($row->V_DOUBLE - $v_double) > abs($v_double / 1E15)) { 76 | echo " DOUBLE fail\n"; 77 | echo " in: $v_double\n"; 78 | echo " out: $row->V_DOUBLE\n"; 79 | } 80 | if(abs($row->V_FLOAT - $v_float) > abs($v_float / 1E7)) { 81 | echo " FLOAT fail\n"; 82 | echo " in: $v_float\n"; 83 | echo " out: $row->V_FLOAT\n"; 84 | } 85 | if($row->V_INTEGER != $v_integer) { 86 | echo " INTEGER fail\n"; 87 | echo " in: $v_integer\n"; 88 | echo " out: $row->V_INTEGER\n"; 89 | } 90 | if ($row->V_NUMERIC != $v_numeric) { 91 | echo " NUMERIC fail\n"; 92 | echo " in: $v_numeric\n"; 93 | echo " out: $row->V_NUMERIC\n"; 94 | } 95 | if ($row->V_SMALLINT != $v_smallint) { 96 | echo " SMALLINT fail\n"; 97 | echo " in: $v_smallint\n"; 98 | echo " out: $row->V_SMALLINT\n"; 99 | } 100 | if ($row->V_VARCHAR != $v_varchar) { 101 | echo " VARCHAR fail:\n"; 102 | echo " in: $v_varchar\n"; 103 | echo " out: $row->V_VARCHAR\n"; 104 | } 105 | ibase_free_result($sel); 106 | }/* for($iter)*/ 107 | 108 | echo "select\n"; 109 | for($iter = 0; $iter < 3; $iter++) { 110 | /* prepare data */ 111 | $v_char = rand_str(1000); 112 | $v_date = (int)rand_number(10,0,0); 113 | $v_decimal = rand_number(12,3); 114 | $v_double = rand_number(20); 115 | $v_float = rand_number(7); 116 | $v_integer = rand_number(9,0); 117 | $v_numeric = rand_number(4,2); 118 | $v_smallint = ((int)rand_number(5)) % 32767; 119 | $v_varchar = rand_str(10000); 120 | 121 | /* clear table*/ 122 | ibase_query("delete from test6"); 123 | 124 | /* make one record */ 125 | ibase_query("insert into test6 126 | (iter, v_char,v_date,v_decimal, 127 | v_integer,v_numeric,v_smallint,v_varchar) 128 | values (666, '$v_char',?,$v_decimal, $v_integer, 129 | $v_numeric, $v_smallint, '$v_varchar')",$v_date); 130 | 131 | /* test all types */ 132 | if(!($sel = ibase_query( 133 | "select iter from test6 where v_char = ?", $v_char)) || 134 | !ibase_fetch_row($sel)) { 135 | echo "CHAR fail\n"; 136 | } 137 | ibase_free_result($sel); 138 | if(!($sel = ibase_query( 139 | "select iter from test6 where v_date = ?", $v_date)) || 140 | !ibase_fetch_row($sel)) { 141 | echo "DATE fail\n"; 142 | } 143 | ibase_free_result($sel); 144 | if(!($sel = ibase_query( 145 | "select iter from test6 where v_decimal = ?", $v_decimal)) || 146 | !ibase_fetch_row($sel)) { 147 | echo "DECIMAL fail\n"; 148 | } 149 | ibase_free_result($sel); 150 | if(!($sel = ibase_query( 151 | "select iter from test6 where v_integer = ?", $v_integer)) || 152 | !ibase_fetch_row($sel)) { 153 | echo "INTEGER fail\n"; 154 | } 155 | ibase_free_result($sel); 156 | if(!($sel = ibase_query( 157 | "select iter from test6 where v_numeric = ?", $v_numeric)) || 158 | !ibase_fetch_row($sel)) { 159 | echo "NUMERIC fail\n"; 160 | } 161 | ibase_free_result($sel); 162 | if(!($sel = ibase_query( 163 | "select iter from test6 where v_smallint = ?", $v_smallint)) || 164 | !ibase_fetch_row($sel)) { 165 | echo "SMALLINT fail\n"; 166 | } 167 | ibase_free_result($sel); 168 | if(!($sel = ibase_query( 169 | "select iter from test6 where v_varchar = ?", $v_varchar)) || 170 | !ibase_fetch_row($sel)) { 171 | echo "VARCHAR fail\n"; 172 | } 173 | ibase_free_result($sel); 174 | 175 | } /*for iter*/ 176 | 177 | echo "prepare and exec insert\n"; 178 | 179 | /* prepare table */ 180 | ibase_query("delete from test6"); 181 | 182 | /* prepare query */ 183 | $query = ibase_prepare( 184 | "insert into test6 (v_integer) values (?)"); 185 | 186 | for($i = 0; $i < 10; $i++) { 187 | ibase_execute($query, $i); 188 | } 189 | 190 | out_table("test6"); 191 | 192 | ibase_free_query($query); 193 | 194 | echo "prepare and exec select\n"; 195 | 196 | /* prepare query */ 197 | $query = ibase_prepare("select * from test6 198 | where v_integer between ? and ?"); 199 | 200 | $low_border = 2; 201 | $high_border = 6; 202 | 203 | $res = ibase_execute($query, $low_border, $high_border); 204 | out_result($res, "test6"); 205 | ibase_free_result($res); 206 | 207 | $low_border = 0; 208 | $high_border = 4; 209 | $res = ibase_execute($query, $low_border, $high_border); 210 | out_result($res, "test6"); 211 | ibase_free_result($res); 212 | 213 | $res = ibase_execute($query, "5", 7.499); 214 | out_result($res, "test6"); 215 | ibase_free_result($res); 216 | 217 | ibase_free_query($query); 218 | 219 | /* test execute procedure */ 220 | $query = ibase_prepare("execute procedure add1(?)"); 221 | $res = array(); 222 | for ($i = 0; $i < 10; $i++) { 223 | $res[] = ibase_execute($query,$i); 224 | } 225 | ibase_free_query($query); 226 | foreach ($res as $r) { 227 | out_result($r, "proc add1"); 228 | ibase_free_result($r); 229 | } 230 | 231 | ibase_close(); 232 | echo "end of test\n"; 233 | ?> 234 | --EXPECT-- 235 | insert 236 | select 237 | prepare and exec insert 238 | --- test6 --- 239 | 0 240 | 1 241 | 2 242 | 3 243 | 4 244 | 5 245 | 6 246 | 7 247 | 8 248 | 9 249 | --- 250 | prepare and exec select 251 | --- test6 --- 252 | 2 253 | 3 254 | 4 255 | 5 256 | 6 257 | --- 258 | --- test6 --- 259 | 0 260 | 1 261 | 2 262 | 3 263 | 4 264 | --- 265 | --- test6 --- 266 | 5 267 | 6 268 | 7 269 | --- 270 | --- proc add1 --- 271 | 1 272 | --- 273 | --- proc add1 --- 274 | 2 275 | --- 276 | --- proc add1 --- 277 | 3 278 | --- 279 | --- proc add1 --- 280 | 4 281 | --- 282 | --- proc add1 --- 283 | 5 284 | --- 285 | --- proc add1 --- 286 | 6 287 | --- 288 | --- proc add1 --- 289 | 7 290 | --- 291 | --- proc add1 --- 292 | 8 293 | --- 294 | --- proc add1 --- 295 | 9 296 | --- 297 | --- proc add1 --- 298 | 10 299 | --- 300 | end of test 301 | -------------------------------------------------------------------------------- /tests/007.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | InterBase: array handling 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | V_CHAR[$i],$v_char[$i],strlen($v_char[$i])) != 0) { 88 | echo " CHAR[$i] fail:\n"; 89 | echo " in: ".$v_char[$i]."\n"; 90 | echo " out: ".$row->V_CHAR[$i]."\n"; 91 | } 92 | if($row->V_DATE[$i] != $v_date[$i]) { 93 | echo " DATE[$i] fail\n"; 94 | echo " in: ".$v_date[$i]."\n"; 95 | echo " out: ".$row->V_DATE[$i]."\n"; 96 | } 97 | if($row->V_DECIMAL[$i] != $v_decimal[$i]) { 98 | echo " DECIMAL[$i] fail\n"; 99 | echo " in: ".$v_decimal[$i]."\n"; 100 | echo " out: ".$row->V_DECIMAL[$i]."\n"; 101 | } 102 | if(abs($row->V_DOUBLE[$i] - $v_double[$i]) > abs($v_double[$i] / 1E15)) { 103 | echo " DOUBLE[$i] fail\n"; 104 | echo " in: ".$v_double[$i]."\n"; 105 | echo " out: ".$row->V_DOUBLE[$i]."\n"; 106 | } 107 | if(abs($row->V_FLOAT[$i] - $v_float[$i]) > abs($v_float[$i] / 1E7)) { 108 | echo " FLOAT[$i] fail\n"; 109 | echo " in: ".$v_float[$i]."\n"; 110 | echo " out: ".$row->V_FLOAT[$i]."\n"; 111 | } 112 | if($row->V_INTEGER[$i] != $v_integer[$i]) { 113 | echo " INTEGER[$i] fail\n"; 114 | echo " in: ".$v_integer[$i]."\n"; 115 | echo " out: ".$row->V_INTEGER[$i]."\n"; 116 | } 117 | if ($row->V_NUMERIC[$i] != $v_numeric[$i]) { 118 | echo " NUMERIC[$i] fail\n"; 119 | echo " in: ".$v_numeric[$i]."\n"; 120 | echo " out: ".$row->V_NUMERIC[$i]."\n"; 121 | } 122 | if ($row->V_SMALLINT[$i] != $v_smallint[$i]) { 123 | echo " SMALLINT[$i] fail\n"; 124 | echo " in: ".$v_smallint[$i]."\n"; 125 | echo " out: ".$row->V_SMALLINT[$i]."\n"; 126 | } 127 | if ($row->V_VARCHAR[$i] != $v_varchar[$i]) { 128 | echo " VARCHAR[$i] fail:\n"; 129 | echo " in: ".$v_varchar[$i]."\n"; 130 | echo " out: ".$row->V_VARCHAR[$i]."\n"; 131 | } 132 | } 133 | ibase_free_result($sel); 134 | }/* for($iter) */ 135 | 136 | echo "select\n"; 137 | 138 | $sel = ibase_query("SELECT v_multi[5,5,5],v_multi[10,10,10] FROM test7 WHERE iter = 0"); 139 | print_r(ibase_fetch_row($sel)); 140 | ibase_free_result($sel); 141 | 142 | for($iter = 1; $iter <= 3; $iter++) { 143 | 144 | if(!($sel = ibase_query( 145 | "select iter from test7 where v_char[$iter] LIKE ?", $v_char[$iter]."%")) || 146 | !ibase_fetch_row($sel)) { 147 | echo "CHAR fail\n"; 148 | } 149 | ibase_free_result($sel); 150 | 151 | if(!($sel = ibase_query( 152 | "select iter from test7 where v_date[$iter] = ?", $v_date[$iter])) || 153 | !ibase_fetch_row($sel)) { 154 | echo "DATE fail\n"; 155 | } 156 | ibase_free_result($sel); 157 | if(!($sel = ibase_query( 158 | "select iter from test7 where v_decimal[$iter] = ?", $v_decimal[$iter])) || 159 | !ibase_fetch_row($sel)) { 160 | echo "DECIMAL fail\n"; 161 | } 162 | ibase_free_result($sel); 163 | if(!($sel = ibase_query( 164 | "select iter from test7 where v_integer[$iter] = ?", $v_integer[$iter])) || 165 | !ibase_fetch_row($sel)) { 166 | echo "INTEGER fail\n"; 167 | } 168 | ibase_free_result($sel); 169 | if(!($sel = ibase_query( 170 | "select iter from test7 where v_numeric[$iter] = ?", $v_numeric[$iter])) || 171 | !ibase_fetch_row($sel)) { 172 | echo "NUMERIC fail\n"; 173 | } 174 | ibase_free_result($sel); 175 | if(!($sel = ibase_query( 176 | "select iter from test7 where v_smallint[$iter] = ?", $v_smallint[$iter])) || 177 | !ibase_fetch_row($sel)) { 178 | echo "SMALLINT fail\n"; 179 | } 180 | ibase_free_result($sel); 181 | } 182 | ibase_close(); 183 | echo "end of test\n"; 184 | ?> 185 | --EXPECT-- 186 | insert 187 | select 188 | Array 189 | ( 190 | [0] => 125 191 | [1] => 1000 192 | ) 193 | end of test 194 | -------------------------------------------------------------------------------- /tests/008.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | InterBase: event handling 3 | --SKIPIF-- 4 | 9 | --FILE-- 10 | 5) echo "FAIL ($count)\n"; 45 | echo "end of test\n"; 46 | 47 | ?> 48 | --EXPECT-- 49 | end of test 50 | -------------------------------------------------------------------------------- /tests/bug45373.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Bug #45373 (php crash on query with errors in params) 3 | --SKIPIF-- 4 | 10 | --FILE-- 11 | 33 | --EXPECTF-- 34 | array(2) { 35 | ["I"]=> 36 | int(1) 37 | ["C"]=> 38 | string(32) "test table not created with isql" 39 | } 40 | 41 | Notice: ibase_execute(): Statement expects 2 arguments, 3 given in %s on line %d 42 | array(2) { 43 | ["I"]=> 44 | int(1) 45 | ["C"]=> 46 | string(32) "test table not created with isql" 47 | } 48 | 49 | Warning: ibase_execute(): Statement expects 2 arguments, 1 given in %s on line %d 50 | 51 | Warning: ibase_fetch_assoc() expects parameter 1 to be resource, bool given in %s on line %d 52 | NULL 53 | -------------------------------------------------------------------------------- /tests/bug45575.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Bug #45575 (Segfault with invalid non-string as event handler callback) 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 19 | --EXPECTF-- 20 | Warning: ibase_set_event_handler(): Callback argument is not a callable function in %s on line %d 21 | 22 | Warning: ibase_set_event_handler(): Callback argument 1 is not a callable function in %s on line %d 23 | -------------------------------------------------------------------------------- /tests/bug46247_001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Bug #46247 (ibase_set_event_handler() is allowing to pass callback without event) 3 | --SKIPIF-- 4 | 8 | --FILE-- 9 | 29 | --EXPECTF-- 30 | Warning: Wrong parameter count for ibase_set_event_handler() in %s on line %d 31 | 32 | Warning: ibase_set_event_handler(): supplied argument is not a valid InterBase link resource in %s on line %d 33 | 34 | Warning: ibase_set_event_handler(): Callback argument foo is not a callable function in %s on line %d 35 | 36 | Warning: ibase_set_event_handler(): Callback argument foo is not a callable function in %s on line %d 37 | 38 | Warning: ibase_set_event_handler(): supplied argument is not a valid InterBase link resource in %s on line %d 39 | -------------------------------------------------------------------------------- /tests/bug46247_002.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Bug #46247 (ibase_set_event_handler() is allowing to pass callback without event) 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 16 | --EXPECTF-- 17 | Warning: ibase_set_event_handler(): Callback argument foo is not a callable function in %s on line %d 18 | 19 | Warning: ibase_set_event_handler(): Callback argument foo is not a callable function in %s on line %d 20 | -------------------------------------------------------------------------------- /tests/bug46247_003.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Bug #46247 (ibase_set_event_handler() is allowing to pass callback without event) 3 | --SKIPIF-- 4 | 8 | --FILE-- 9 | 20 | --EXPECTF-- 21 | Fatal error: Uncaught ArgumentCountError: Wrong parameter count for ibase_set_event_handler() in %a 22 | -------------------------------------------------------------------------------- /tests/bug46247_004.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Bug #46247 (ibase_set_event_handler() is allowing to pass callback without event) 3 | --SKIPIF-- 4 | 8 | --FILE-- 9 | 20 | --EXPECTF-- 21 | Fatal error: Uncaught TypeError: ibase_set_event_handler(): supplied argument is not a valid InterBase link resource in %a 22 | -------------------------------------------------------------------------------- /tests/bug46543.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Bug #46543 (ibase_trans() memory leaks when using wrong parameters) 3 | --SKIPIF-- 4 | 10 | --FILE-- 11 | 26 | --EXPECTF-- 27 | Warning: ibase_trans(): supplied resource is not a valid Firebird/InterBase link resource in %sbug46543.php on line %d 28 | 29 | Warning: ibase_trans(): supplied resource is not a valid Firebird/InterBase link resource in %sbug46543.php on line %d 30 | 31 | Warning: ibase_trans(): supplied resource is not a valid Firebird/InterBase link resource in %sbug46543.php on line %d 32 | 33 | Warning: ibase_trans(): supplied resource is not a valid Firebird/InterBase link resource in %sbug46543.php on line %d 34 | -------------------------------------------------------------------------------- /tests/config.inc: -------------------------------------------------------------------------------- 1 | 7 | --FILE-- 8 | 33 | --EXPECTF-- 34 | array(3) { 35 | ["V_CHAR_UTF8_1"]=> 36 | string(3) "€" 37 | ["V_CHAR_UTF8_10"]=> 38 | string(12) " A € " 39 | ["V_VARCHAR_UTF8_1"]=> 40 | string(3) "€" 41 | } 42 | -------------------------------------------------------------------------------- /tests/datatype_int128.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for data type INT128 (Firebird 4.0 or above) 3 | --SKIPIF-- 4 | 7 | --FILE-- 8 | 34 | --EXPECTF-- 35 | array(1) { 36 | ["V_INT128"]=> 37 | string(4) "1234" 38 | } 39 | array(1) { 40 | ["V_INT128"]=> 41 | string(40) "-170141183460469231731687303715884105728" 42 | } 43 | array(1) { 44 | ["V_INT128"]=> 45 | string(39) "170141183460469231731687303715884105727" 46 | } 47 | -------------------------------------------------------------------------------- /tests/functions.inc: -------------------------------------------------------------------------------- 1 | 5 | --FILE-- 6 | 27 | --EXPECTF-- 28 | int(3) 29 | int(0) 30 | 31 | Warning: ibase_query(): Dynamic SQL Error SQL error code = -104 %s on line %d 32 | int(0) 33 | -------------------------------------------------------------------------------- /tests/ibase_close_001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | ibase_close(): Basic test 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 16 | --EXPECTF-- 17 | bool(true) 18 | bool(true) 19 | bool(true) 20 | -------------------------------------------------------------------------------- /tests/ibase_close_002.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | ibase_close(): Make sure passing a string to the function emits a warning 3 | --SKIPIF-- 4 | 8 | --FILE-- 9 | 20 | --EXPECTF-- 21 | bool(true) 22 | bool(true) 23 | bool(true) 24 | 25 | Warning: ibase_close() expects parameter 1 to be resource, string given in %s on line %d 26 | NULL 27 | -------------------------------------------------------------------------------- /tests/ibase_close_003.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | ibase_close(): Make sure passing a string to the function throws an error. 3 | --SKIPIF-- 4 | 8 | --FILE-- 9 | 20 | --EXPECTF-- 21 | bool(true) 22 | bool(true) 23 | bool(true) 24 | 25 | Fatal error: Uncaught TypeError: ibase_close(): Argument #1 ($link_identifier) must be of type resource, string given in %a 26 | -------------------------------------------------------------------------------- /tests/ibase_commit_001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | ibase_commit(): Make sure the method can be invoked with zero arguments 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 17 | --EXPECTF-- 18 | bool(true) 19 | -------------------------------------------------------------------------------- /tests/ibase_commit_ret_001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | ibase_commit_ret(): Make sure the method can be invoked with zero arguments 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 17 | --EXPECTF-- 18 | bool(true) 19 | -------------------------------------------------------------------------------- /tests/ibase_drop_db_001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | ibase_drop_db(): Basic test 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 21 | --EXPECTF-- 22 | resource(%d) of type (Firebird/InterBase link) 23 | bool(true) 24 | -------------------------------------------------------------------------------- /tests/ibase_drop_db_002.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | ibase_drop_db(): Make sure passing an integer or null to the function emits a warning 3 | --SKIPIF-- 4 | 8 | --FILE-- 9 | 25 | --EXPECTF-- 26 | resource(%d) of type (Firebird/InterBase link) 27 | bool(true) 28 | 29 | Warning: ibase_drop_db() expects parameter 1 to be resource, int given in %s on line %d 30 | NULL 31 | 32 | Warning: ibase_drop_db() expects parameter 1 to be resource, null given in %s on line %d 33 | NULL 34 | -------------------------------------------------------------------------------- /tests/ibase_drop_db_003.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | ibase_drop_db(): Make sure passing an integer to the function throws an error. 3 | --SKIPIF-- 4 | 8 | --FILE-- 9 | 25 | --EXPECTF-- 26 | resource(%d) of type (Firebird/InterBase link) 27 | bool(true) 28 | 29 | Fatal error: Uncaught TypeError: ibase_drop_db(): Argument #1 ($link_identifier) must be of type resource, int given in %a 30 | -------------------------------------------------------------------------------- /tests/ibase_drop_db_004.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | ibase_drop_db(): Make sure passing null to the function throws an error. 3 | --SKIPIF-- 4 | 8 | --FILE-- 9 | 25 | --EXPECTF-- 26 | resource(%d) of type (Firebird/InterBase link) 27 | bool(true) 28 | 29 | Fatal error: Uncaught TypeError: ibase_drop_db(): Argument #1 ($link_identifier) must be of type resource, null given in %a 30 | -------------------------------------------------------------------------------- /tests/ibase_errmsg_001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | ibase_errmsg(): Basic test 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 19 | --EXPECTF-- 20 | Warning: ibase_query(): Dynamic SQL Error SQL error code = -104 %s on line %d 21 | string(%d) "Dynamic SQL Error SQL error code = -104 %s" 22 | bool(false) 23 | -------------------------------------------------------------------------------- /tests/ibase_free_query_001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | ibase_free_query(): Basic test 3 | --SKIPIF-- 4 | 8 | --FILE-- 9 | 24 | --EXPECTF-- 25 | bool(true) 26 | 27 | Warning: ibase_free_query(): supplied resource is not a valid Firebird/InterBase query resource in %s on line %d 28 | bool(false) 29 | 30 | Warning: ibase_free_query(): supplied resource is not a valid Firebird/InterBase query resource in %s on line %d 31 | bool(false) 32 | -------------------------------------------------------------------------------- /tests/ibase_free_query_002.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | ibase_free_query(): Basic test 3 | --SKIPIF-- 4 | 8 | --FILE-- 9 | 24 | --EXPECTF-- 25 | bool(true) 26 | 27 | Fatal error: Uncaught TypeError: ibase_free_query(): supplied resource is not a valid Firebird/InterBase query resource in %a -------------------------------------------------------------------------------- /tests/ibase_num_fields_001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | ibase_num_fields(): Basic test 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 15 | --EXPECTF-- 16 | int(2) 17 | -------------------------------------------------------------------------------- /tests/ibase_num_fields_002.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | ibase_num_fields(): Make sure passing an integer or zero args to the function emits a warning 3 | --SKIPIF-- 4 | 8 | --FILE-- 9 | 15 | --EXPECTF-- 16 | Warning: ibase_num_fields() expects parameter 1 to be resource, int given in %s on line %d 17 | NULL 18 | 19 | Warning: ibase_num_fields() expects exactly 1 parameter, 0 given in %s on line %d 20 | NULL 21 | -------------------------------------------------------------------------------- /tests/ibase_num_fields_003.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | ibase_num_fields(): Make sure passing an integer to the function throws an error. 3 | --SKIPIF-- 4 | 8 | --FILE-- 9 | 14 | --EXPECTF-- 15 | Fatal error: Uncaught TypeError: ibase_num_fields(): Argument #1 ($query_result) must be of type resource, int given in %a 16 | -------------------------------------------------------------------------------- /tests/ibase_num_fields_004.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | ibase_num_fields(): Make sure passing zero arguments to the function throws an error 3 | --SKIPIF-- 4 | 8 | --FILE-- 9 | 14 | --EXPECTF-- 15 | Fatal error: Uncaught ArgumentCountError: ibase_num_fields() expects exactly 1 argument, 0 given in %a 16 | -------------------------------------------------------------------------------- /tests/ibase_num_params_001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | ibase_num_params(): Basic test 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 16 | --EXPECTF-- 17 | int(2) 18 | -------------------------------------------------------------------------------- /tests/ibase_num_params_002.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | ibase_num_params(): Basic test 3 | --SKIPIF-- 4 | 8 | --FILE-- 9 | 26 | --EXPECTF-- 27 | int(2) 28 | 29 | Warning: ibase_num_params() expects exactly 1 parameter, 0 given in %s on line %d 30 | NULL 31 | 32 | Warning: ibase_prepare(): Dynamic SQL Error SQL error code = -206 %s in %s on line %d 33 | 34 | Warning: ibase_num_params() expects parameter 1 to be resource, bool given in %s on line %d 35 | NULL 36 | -------------------------------------------------------------------------------- /tests/ibase_num_params_003.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | ibase_num_params(): Basic test 3 | --SKIPIF-- 4 | 8 | --FILE-- 9 | 22 | --EXPECTF-- 23 | int(2) 24 | 25 | Fatal error: Uncaught ArgumentCountError: ibase_num_params() expects exactly 1 argument, 0 given in %a -------------------------------------------------------------------------------- /tests/ibase_num_params_004.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | ibase_num_params(): Basic test 3 | --SKIPIF-- 4 | 8 | --FILE-- 9 | 22 | --EXPECTF-- 23 | int(2) 24 | 25 | Warning: ibase_prepare(): Dynamic SQL Error SQL error code = -%d Column unknown X At line %d, column %d %s 26 | 27 | Fatal error: Uncaught TypeError: ibase_num_params(): Argument #1 ($query) must be of type resource, %a -------------------------------------------------------------------------------- /tests/ibase_param_info_001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | ibase_param_info(): Basic test 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 20 | --EXPECTF-- 21 | array(10) { 22 | [0]=> 23 | string(0) "" 24 | ["name"]=> 25 | string(0) "" 26 | [1]=> 27 | string(0) "" 28 | ["alias"]=> 29 | string(0) "" 30 | [2]=> 31 | string(0) "" 32 | ["relation"]=> 33 | string(0) "" 34 | [3]=> 35 | string(1) "4" 36 | ["length"]=> 37 | string(1) "4" 38 | [4]=> 39 | string(7) "INTEGER" 40 | ["type"]=> 41 | string(7) "INTEGER" 42 | } 43 | --- 44 | bool(false) 45 | -------------------------------------------------------------------------------- /tests/ibase_param_info_002.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | ibase_param_info(): Error if called with a single argument 3 | --SKIPIF-- 4 | 8 | --FILE-- 9 | 14 | --EXPECTF-- 15 | Warning: ibase_param_info() expects exactly 2 parameters, 1 given in %s on line %d 16 | NULL 17 | -------------------------------------------------------------------------------- /tests/ibase_param_info_003.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | ibase_param_info(): Error if called with a single argument 3 | --SKIPIF-- 4 | 8 | --FILE-- 9 | 14 | --EXPECTF-- 15 | Fatal error: Uncaught ArgumentCountError: ibase_param_info() expects exactly 2 arguments, 1 given in %a 16 | -------------------------------------------------------------------------------- /tests/ibase_rollback_001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | ibase_rollback(): Basic test 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 28 | --EXPECTF-- 29 | array(1) { 30 | [0]=> 31 | int(3) 32 | } 33 | bool(true) 34 | array(1) { 35 | [0]=> 36 | int(0) 37 | } 38 | bool(true) 39 | 40 | Warning: ibase_rollback(): invalid transaction handle (expecting explicit transaction start) in %s on line %d 41 | bool(false) 42 | -------------------------------------------------------------------------------- /tests/ibase_rollback_002.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | ibase_rollback(): Make sure the method can be invoked with zero arguments 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 17 | --EXPECTF-- 18 | bool(true) 19 | -------------------------------------------------------------------------------- /tests/ibase_rollback_ret_001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | ibase_rollback_ret(): Make sure the method can be invoked with zero arguments 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 17 | --EXPECTF-- 18 | bool(true) 19 | -------------------------------------------------------------------------------- /tests/ibase_trans_001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | ibase_trans(): Basic test 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 17 | --EXPECTF-- 18 | resource(%d) of type (Firebird/InterBase transaction) 19 | resource(%d) of type (Firebird/InterBase transaction) 20 | bool(true) 21 | bool(true) 22 | -------------------------------------------------------------------------------- /tests/ibase_trans_002.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | ibase_trans(): Basic operations 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 27 | --EXPECT-- 28 | int(1) 29 | array(2) { 30 | ["I"]=> 31 | int(100) 32 | ["C"]=> 33 | string(3) "100" 34 | } 35 | -------------------------------------------------------------------------------- /tests/ibase_trans_003.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | ibase_trans(): Check order of link identifier and trans args 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 19 | --EXPECT-- 20 | Could not insert 21 | -------------------------------------------------------------------------------- /tests/interbase.inc: -------------------------------------------------------------------------------- 1 | = 8.0'); 4 | } 5 | ?> 6 | -------------------------------------------------------------------------------- /tests/skipif-php8-or-newer.inc: -------------------------------------------------------------------------------- 1 | = 8) { 3 | die('skip: This test verifies behavior that can only be observed in PHP versions < 8.0'); 4 | } 5 | ?> 6 | -------------------------------------------------------------------------------- /tests/skipif.inc: -------------------------------------------------------------------------------- 1 | 9 | --------------------------------------------------------------------------------