9 Commits
0.4.0 ... v0.x

Author SHA1 Message Date
macintoshplus
d1c4cdc291 bump version to 0.4.1 2026-02-27 11:56:58 +01:00
macintoshplus
1931258612 🐛 apply patch for PHP 8 Thanks @arekm
📝 add readme
2026-02-27 11:55:09 +01:00
macintoshplus
f2b2ca9e3f add config PIE and GitHub Action 2026-02-26 22:08:01 +01:00
Simon Bazley
403fa58b6f Merge pull request #3 from krejcipetr/master
Repair the returning matches
2024-08-05 11:06:50 +01:00
Simon Bazley
832872beac Merge pull request #5 from lachbaer/fix_match_array
Fix issue #4 - match array not initialized
2024-08-05 11:06:21 +01:00
Simon Bazley
3fb8cf045d Merge pull request #6 from RobWei/master
Added code support for PHP 8
2024-08-05 11:05:51 +01:00
RobWei
60eb6b9f16 Added code support for PHP 8 2024-01-23 11:17:56 +01:00
Eik Rentzow
cc2e72e3d2 Fix issue #4 - match array not initialized
Done like in function php_pcre_match_impl() of PCRE module.
2023-02-28 08:14:33 +01:00
Petr Krejčí
d19b005e00 Repair the returning matches 2022-12-13 21:55:15 +01:00
10 changed files with 386 additions and 17 deletions

13
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,13 @@
# These are supported funding model platforms
github: [macintoshplus] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
# patreon: # Replace with a single Patreon username
# open_collective: # Replace with a single Open Collective username
# ko_fi: # Replace with a single Ko-fi username
# tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
# community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
# liberapay: # Replace with a single Liberapay username
# issuehunt: # Replace with a single IssueHunt username
# otechie: # Replace with a single Otechie username
# lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
# custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

130
.github/windows.yml vendored Normal file
View File

@@ -0,0 +1,130 @@
name: Publish Windows Releases
on:
workflow_dispatch: ~
release:
types: [created]
push:
branches: ['*']
permissions:
contents: write
jobs:
build-lib:
runs-on: windows-2022
strategy:
fail-fast: true
matrix:
# arch: [x64, x86]
arch: [x64]
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Enable Developer Command Prompt
uses: ilammy/msvc-dev-cmd@v1
with:
arch: ${{ matrix.arch }}
- name: Build the library
run: |
mkdir tcl
cd tcl
Invoke-WebRequest -Uri https://github.com/tcltk/tcl/releases/download/core-9-0-3/tcl9.0.3-src.tar.gz -outFile tcl.tar.gz
7z x tcl.tar.gz -so | 7z x -aoa -si -ttar -o"."
cd tcl9.0.3\win
mkdir install
nmake -f Makefile.vc all INSTALLDIR=.\install
nmake -f Makefile.vc install INSTALLDIR=.\install
7z a tcl.zip .\install
- name: Upload TCL library
uses: actions/upload-artifact@v5
with:
name: tcl-${{ matrix.arch }}
path: tcl\tcl9.0.3\win\tcl.zip
if-no-files-found: error
get-extension-matrix:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.extension-matrix.outputs.matrix }}
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Get the extension matrix
id: extension-matrix
uses: php/php-windows-builder/extension-matrix@v1
with:
arch-list: x64
php-version-list: "8.0"
ts-list: nts
build:
needs: [get-extension-matrix, build-lib]
runs-on: ${{ matrix.os }}
continue-on-error: false
strategy:
fail-fast: true
matrix: ${{fromJson(needs.get-extension-matrix.outputs.matrix)}}
steps:
- name: Checkout
uses: actions/checkout@v5
- name: prepare
run: |
mkdir ..\tcl
- name: Download native lib
uses: actions/download-artifact@v5
with:
name: tcl-${{ matrix.arch }}
- name: Extract native lib
run: |
dir
7z x tcl.zip -o"..\tcl"
dir ..
dir ..\tcl
dir ..\tcl\install\include
dir ..\tcl\install\lib
- name: Setup PHP SDK
id: setup-php-windows
uses: php/setup-php-sdk@v0.12
with:
version: ${{ matrix.php-version }}
arch: ${{ matrix.arch }}
ts: ${{ matrix.ts }}
- name: Enable Developer Command Prompt
uses: ilammy/msvc-dev-cmd@v1
with:
arch: ${{ matrix.arch }}
toolset: ${{ steps.setup-php-windows.outputs.toolset }}
- run: phpize
- run: ./configure --with-expect --with-extra-includes="$($Env:GITHUB_WORKSPACE)..\tcl\install\include" --with-extra-libs="$($Env:GITHUB_WORKSPACE)..\tcl\install\lib" --with-prefix=${{steps.setup-php-windows.outputs.prefix}}
- run: nmake
- run: nmake test TESTS=tests
# - name: Upload TCL library
# uses: actions/upload-artifact@v5
# with:
# name: tcl-${{ matrix.php }}-${{ matrix.arch }}
# path: |
# win\install\
# - name: Build the extension
# uses: php/php-windows-builder/extension@v1
# with:
# php-version: ${{ matrix.php-version }}
# arch: ${{ matrix.arch }}
# ts: ${{ matrix.ts }}
# args: '--with-expect'
release:
runs-on: ubuntu-latest
needs: build
if: ${{ github.event_name == 'release' }}
steps:
- name: Upload artifact to the release
uses: php/php-windows-builder/release@v1
with:
release: ${{ github.event.release.tag_name }}

35
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,35 @@
name: CI
on:
push:
branches: ['*']
jobs:
test-linux:
runs-on: ubuntu-latest
strategy:
fail-fast: true
matrix:
php-rel: ['8.0', '8.1', '8.2', '8.3', '8.4', '8.5']
# php-rel: ['8.0']
ts-state: [ts, nts]
steps:
- uses: actions/checkout@v5
- name: Install dependencies
run: sudo apt-get install -y tcl-dev tcl-expect-dev
- name: Setup PHP
id: setup-php
uses: shivammathur/setup-php@v2
with:
php-version: '${{ matrix.php-rel }}'
env:
phpts: '${{ matrix.ts-state }}'
- name: build extension
env:
CPPFLAGS: -I/usr/include/tcl
run: |
phpize
./configure --with-expect
make
- name: run tests
run: make test

25
.gitignore vendored Normal file
View File

@@ -0,0 +1,25 @@
/config.h
/config.h.in
/config.log
/config.nice
/config.status
/configure
/configure.ac
/expect.la
/expect.lo
/expect_fopen_wrapper.lo
/libtool
/Makefile
/Makefile.fragments
/Makefile.objects
/run-tests.php
/tests/*.diff
/tests/*.exp
/tests/*.log
/tests/*.php
/tests/*.out
/tests/*.sh
/.libs/
/autom4te.cache/
/build/
/modules/

71
README.md Normal file
View File

@@ -0,0 +1,71 @@
PHP extension for expect library
================================
This extension allows to interact with processes through PTY, using expect library.
This extension uses a Tcl/Expect library: https://www.tcl-lang.org/.
Original author: Michael Spector
> **Unable to build this extension for Windows because the TCL Expect is not available on Windows.**
Maintained branches:
| Version | Status |
|---------|------------------------------|
| master | unmaintened :x: |
| v0.x | maintened :white_check_mark: |
Maintained PHP Versions compatibility:
| PHP Version | Status |
|-------------|------------------------|
| 5.x | no :x: |
| 7.x | no :x: |
| 8.0 | yes :white_check_mark: |
| 8.1 | yes :white_check_mark: |
| 8.2 | yes :white_check_mark: |
| 8.3 | yes :white_check_mark: |
| 8.4 | yes :white_check_mark: |
| 8.5 | yes :white_check_mark: |
Installation system support:
| Platform | Status |
|----------|------------------------|
| PECL | no :x: |
| PIE | yes :white_check_mark: |
To install the extension, install the library `tcl-dev tcl-expect-dev` first.
Debian/Ubuntu/Mint:
```shell
sudo apt-get install tcl-dev tcl-expect-dev
```
Alpine Linux:
```shell
apk add tcl-dev expect-dev
```
Fedora:
```shell
sudo dnf install tcl-devel expect-devel
```
Arch Linux:
```shell
sudo pacman -S tcl expect
```
And use PIE (PHP Installer Extension) with a command like:
```bash
pie install php-win-ext/expect
```

21
composer.json Normal file
View File

@@ -0,0 +1,21 @@
{
"name": "php-win-ext/expect",
"type": "php-ext",
"license": [
"PHP-3.01"
],
"authors": [
{
"name": "Michael Spector",
"email": "michael@php.net"
}
],
"require": {
"php": ">= 8.0.0"
},
"php-ext": {
"extension-name": "expect",
"os-families-exclude": ["windows"]
},
"description": "This extension allows to interact with processes through PTY, using expect library."
}

View File

@@ -1,6 +1,6 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 and 7 |
| PHP Version 5, 7 and 8 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2004 The PHP Group |
+----------------------------------------------------------------------+
@@ -53,7 +53,7 @@ zend_module_entry expect_module_entry = {
expect_functions,
PHP_MINIT(expect),
PHP_MSHUTDOWN(expect),
NULL,
PHP_RINIT(expect),
NULL,
PHP_MINFO(expect),
PHP_EXPECT_VERSION,
@@ -151,8 +151,18 @@ static PHP_INI_MH(OnSetExpectLogUser)
* */
static PHP_INI_MH(OnSetExpectLogFile)
{
/* PHP streams cannot be opened during module startup because the resource
* list (EG(regular_list)) is not yet initialized. The logfile will be
* opened in RINIT once the request context is available. */
if (stage == PHP_INI_STAGE_STARTUP || stage == PHP_INI_STAGE_SHUTDOWN) {
return SUCCESS;
}
if (EXPECT_G(logfile_stream)) {
php_stream_close(EXPECT_G(logfile_stream));
EXPECT_G(logfile_stream) = NULL;
exp_logfile = NULL;
exp_logfile_all = 0;
}
#if PHP_MAJOR_VERSION >= 7
if (ZSTR_LEN(new_value) > 0) {
@@ -232,6 +242,28 @@ PHP_MSHUTDOWN_FUNCTION(expect)
/* }}} */
/* {{{ PHP_RINIT_FUNCTION
* Apply ini settings that require PHP streams, skipped during MINIT. */
PHP_RINIT_FUNCTION(expect)
{
if (!EXPECT_G(logfile_stream)) {
char *logfile = zend_ini_string("expect.logfile", sizeof("expect.logfile") - 1, 0);
if (logfile && strlen(logfile) > 0) {
php_stream *stream = php_stream_open_wrapper(logfile, "a", 0, NULL);
if (stream) {
stream->flags |= PHP_STREAM_FLAG_NO_SEEK;
if (php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void **) &exp_logfile, REPORT_ERRORS) == SUCCESS) {
EXPECT_G(logfile_stream) = stream;
exp_logfile_all = 1;
}
}
}
}
return SUCCESS;
}
/* }}} */
/* {{{ PHP_MINFO_FUNCTION */
PHP_MINFO_FUNCTION(expect)
{
@@ -287,6 +319,10 @@ PHP_FUNCTION(expect_popen)
}
stream->flags |= PHP_STREAM_FLAG_NO_SEEK;
/* PTY reads may return EIO when the child exits; suppress notices (PHP 7.4+ d59aac58b3e7). */
#ifdef PHP_STREAM_FLAG_SUPPRESS_ERRORS
stream->flags |= PHP_STREAM_FLAG_SUPPRESS_ERRORS;
#endif
#if PHP_MAJOR_VERSION >= 7
ZVAL_LONG (&z_pid, exp_pid);
@@ -309,16 +345,20 @@ PHP_FUNCTION(expect_expectl)
struct exp_case *ecases, *ecases_ptr, matchedcase;
#if PHP_MAJOR_VERSION >= 7
zval *z_stream, *z_cases, *z_match=NULL, *z_case, *z_value;
zend_ulong key;
#else
zval *z_stream, *z_cases, *z_match=NULL, **z_case, **z_value;
ulong key;
#endif
php_stream *stream;
int fd, argc;
ulong key;
#if PHP_MAJOR_VERSION >= 7
HashPosition pos;
#endif
if (ZEND_NUM_ARGS() < 2 || ZEND_NUM_ARGS() > 3) { WRONG_PARAM_COUNT; }
if (zend_parse_parameters (ZEND_NUM_ARGS() TSRMLS_CC, "ra|z", &z_stream, &z_cases, &z_match) == FAILURE) {
if (zend_parse_parameters (ZEND_NUM_ARGS() TSRMLS_CC, "ra|z/", &z_stream, &z_cases, &z_match) == FAILURE) {
return;
}
@@ -329,7 +369,7 @@ PHP_FUNCTION(expect_expectl)
#endif
#if PHP_MAJOR_VERSION >= 7
if (!&(stream->wrapperdata)) {
if (Z_TYPE(stream->wrapperdata) != IS_LONG) {
#else
if (!stream->wrapperdata) {
#endif
@@ -345,16 +385,17 @@ PHP_FUNCTION(expect_expectl)
ecases = (struct exp_case*) safe_emalloc (argc + 1, sizeof(struct exp_case), 0);
ecases_ptr = ecases;
zend_hash_internal_pointer_reset (Z_ARRVAL_P(z_cases));
#if PHP_MAJOR_VERSION >= 7
while ((z_case = zend_hash_get_current_data (Z_ARRVAL_P(z_cases))) != NULL)
zend_hash_internal_pointer_reset_ex (Z_ARRVAL_P(z_cases), &pos);
while ((z_case = zend_hash_get_current_data_ex (Z_ARRVAL_P(z_cases), &pos)) != NULL)
{
zval *z_pattern, *z_exp_type;
zend_hash_get_current_key(Z_ARRVAL_P(z_cases), NULL, &key);
zend_hash_get_current_key_ex(Z_ARRVAL_P(z_cases), NULL, &key, &pos);
if (Z_TYPE_P(z_case) != IS_ARRAY) {
#else
zend_hash_internal_pointer_reset (Z_ARRVAL_P(z_cases));
while (zend_hash_get_current_data (Z_ARRVAL_P(z_cases), (void **)&z_case) == SUCCESS)
{
zval **z_pattern, **z_exp_type;
@@ -436,7 +477,11 @@ PHP_FUNCTION(expect_expectl)
}
ecases_ptr++;
#if PHP_MAJOR_VERSION >= 7
zend_hash_move_forward_ex(Z_ARRVAL_P(z_cases), &pos);
#else
zend_hash_move_forward(Z_ARRVAL_P(z_cases));
#endif
}
ecases_ptr->pattern = NULL;
ecases_ptr->re = NULL;
@@ -452,11 +497,19 @@ PHP_FUNCTION(expect_expectl)
if (z_match && exp_match && exp_match_len > 0) {
char *tmp = (char *)emalloc (sizeof(char) * (exp_match_len + 1));
strlcpy (tmp, exp_match, exp_match_len + 1);
zval_dtor (z_match);
array_init(z_match);
#if PHP_MAJOR_VERSION >= 7
#if PHP_MAJOR_VERSION > 7 || (PHP_MAJOR_VERSION == 7 && PHP_MINOR_VERSION >= 4)
z_match = zend_try_array_init(z_match);
if (!z_match) {
return;
}
add_index_string(z_match, 0, tmp);
#elif PHP_MAJOR_VERSION >= 7
zval_dtor(z_match);
array_init(z_match);
add_index_string(z_match, 0, tmp);
#else
zval_dtor (z_match);
array_init(z_match);
add_index_string(z_match, 0, tmp, 1);
#endif
/* Get case that was matched */

View File

@@ -26,6 +26,9 @@
#if PHP_MAJOR_VERSION >= 7
php_stream *php_expect_stream_open (php_stream_wrapper *wrapper, const char *command, const char *mode, int options,
zend_string **opened_command, php_stream_context *context STREAMS_DC TSRMLS_DC)
#elif PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 6
php_stream *php_expect_stream_open (php_stream_wrapper *wrapper, const char *command, const char *mode, int options,
char **opened_command, php_stream_context *context STREAMS_DC TSRMLS_DC)
#else
php_stream *php_expect_stream_open (php_stream_wrapper *wrapper, char *command, char *mode, int options,
char **opened_command, php_stream_context *context STREAMS_DC TSRMLS_DC)
@@ -36,12 +39,17 @@ php_stream *php_expect_stream_open (php_stream_wrapper *wrapper, char *command,
command += sizeof("expect://")-1;
}
#if PHP_MAJOR_VERSION >= 7
#if PHP_MAJOR_VERSION >= 7 || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 6)
if ((fp = exp_popen((char*)command)) != NULL) {
#else
if ((fp = exp_popen(command)) != NULL) {
#endif
php_stream* stream = php_stream_fopen_from_pipe (fp, mode);
stream->flags |= PHP_STREAM_FLAG_NO_SEEK;
/* PTY reads may return EIO when the child exits; suppress notices (PHP 7.4+ d59aac58b3e7). */
#ifdef PHP_STREAM_FLAG_SUPPRESS_ERRORS
stream->flags |= PHP_STREAM_FLAG_SUPPRESS_ERRORS;
#endif
#if PHP_MAJOR_VERSION >= 7
zval z_pid;
ZVAL_LONG (&z_pid, exp_pid);

View File

@@ -51,7 +51,7 @@ http://pear.php.net/dtd/package-2.0.xsd">
<required>
<php>
<min>4.0.0</min>
<max>7.99.99</max>
<max>8.99.99</max>
</php>
<pearinstaller>
<min>1.4.0b1</min>

View File

@@ -1,6 +1,6 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 and 7 |
| PHP Version 5, 7 and 8 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2004 The PHP Group |
+----------------------------------------------------------------------+
@@ -37,7 +37,7 @@
extern zend_module_entry expect_module_entry;
#define phpext_expect_ptr &expect_module_entry
#define PHP_EXPECT_VERSION "0.3.4"
#define PHP_EXPECT_VERSION "0.4.1"
#ifdef PHP_WIN32
#define PHP_EXPECT_API __declspec(dllexport)
@@ -47,6 +47,7 @@ extern zend_module_entry expect_module_entry;
PHP_MINIT_FUNCTION(expect);
PHP_MSHUTDOWN_FUNCTION(expect);
PHP_RINIT_FUNCTION(expect);
PHP_MINFO_FUNCTION(expect);
PHP_FUNCTION(expect_popen);
@@ -68,6 +69,18 @@ ZEND_END_MODULE_GLOBALS(expect)
#include "TSRM.h"
#endif /* ZTS */
#if ZEND_MODULE_API_NO >= 20190128
#ifndef TSRMLS_CC
#define TSRMLS_CC
#endif
#ifndef TSRMLS_DC
#define TSRMLS_DC
#endif
#ifndef TSRMLS_FETCH
#define TSRMLS_FETCH()
#endif
#endif
#endif /* PHP_EXPECT_H */
/*