├── .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 |
--------------------------------------------------------------------------------