Skip to content

Commit

Permalink
Add more missing mysqli features
Browse files Browse the repository at this point in the history
  • Loading branch information
bgrgicak committed Jan 10, 2025
1 parent c61885a commit d740fea
Show file tree
Hide file tree
Showing 5 changed files with 261 additions and 6 deletions.
158 changes: 157 additions & 1 deletion packages/php-wasm/compile/php-wasm-mysqli-polyfill/mysqli_polyfill.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
#include "mysqli_polyfill.h"
#include "zend_API.h"
#include "ext/standard/info.h"
#include "zend_interfaces.h"
#include "zend_exceptions.h"
#include "zend_objects.h"
/* }}} */

/* {{{ PHP_FUNCTION(mysqli_report) */
Expand All @@ -15,9 +18,150 @@ PHP_FUNCTION(mysqli_report)
}
/* }}} */

/* {{{ PHP_FUNCTION(mysqli_get_server_info) */
PHP_FUNCTION(mysqli_get_server_info)
{
const char *version_prefix = "php-wasm-";
char version[strlen(version_prefix) + strlen(PHP_MYSQLI_POLYFILL_VERSION) + 1];
strcat(strcpy(version, version_prefix), PHP_MYSQLI_POLYFILL_VERSION);
RETURN_STRING(version);
}
/* }}} */

zend_class_entry *get_mysqli_class_instance()
{
zend_class_entry *ce;
zend_string *mysqli_class_name = zend_string_init("mysqli", strlen("mysqli"), 0);
ce = zend_fetch_class(mysqli_class_name, ZEND_FETCH_CLASS_DEFAULT);
zend_string_release(mysqli_class_name);
return ce;
}

/* {{{ PHP_FUNCTION(mysqli_init) */
PHP_FUNCTION(mysqli_init)
{
zend_class_entry *ce = get_mysqli_class_instance();

if (!ce)
{
RETURN_FALSE;
}

object_init_ex(return_value, ce);
}
/* }}} */

/* {{{ PHP_FUNCTION(mysqli_connect) */
PHP_FUNCTION(mysqli_connect)
{
zend_class_entry *ce = get_mysqli_class_instance();

if (!ce)
{
RETURN_FALSE;
}

object_init_ex(return_value, ce);
}
/* }}} */

/* {{{ PHP_FUNCTION(mysqli_real_connect) */
PHP_FUNCTION(mysqli_real_connect)
{
RETURN_TRUE;
}
/* }}} */

/* {{{ PHP_FUNCTION(mysqli_query) */
PHP_FUNCTION(mysqli_query)
{
RETURN_TRUE;
}
/* }}} */

/* {{{ PHP_FUNCTION(mysqli_fetch_array) */
PHP_FUNCTION(mysqli_fetch_array)
{
RETURN_NULL();
}
/* }}} */

/* {{{ PHP_FUNCTION(mysqli_select_db) */
PHP_FUNCTION(mysqli_select_db)
{
RETURN_TRUE;
}
/* }}} */

/* {{{ PHP_FUNCTION(mysqli_close) */
PHP_FUNCTION(mysqli_close)
{
RETURN_TRUE;
}
/* }}} */

/* {{{ PHP_FUNCTION(mysqli_real_escape_string) */
PHP_FUNCTION(mysqli_real_escape_string)
{
char *string;
RETURN_STRING(string);
}
/* }}} */

/* {{{ PHP_FUNCTION(mysqli_errno) */
PHP_FUNCTION(mysqli_errno)
{
RETURN_LONG(0);
}
/* }}} */

/* {{{ PHP_FUNCTION(mysqli_error) */
PHP_FUNCTION(mysqli_error)
{
RETURN_STRING("");
}
/* }}} */

/* {{{ PHP_MINIT_FUNCTION */
PHP_MINIT_FUNCTION(mysqli_polyfill)
{
zend_class_entry ce;
zend_class_entry *mysqli_ce;

// Initialize the class entry
INIT_CLASS_ENTRY(ce, "mysqli", NULL);
mysqli_ce = zend_register_internal_class(&ce);

// Add default properties
zend_declare_property_string(mysqli_ce, "host", strlen("host"), "", ZEND_ACC_PUBLIC);
zend_declare_property_string(mysqli_ce, "username", strlen("username"), "", ZEND_ACC_PUBLIC);
zend_declare_property_string(mysqli_ce, "password", strlen("password"), "", ZEND_ACC_PUBLIC);
zend_declare_property_string(mysqli_ce, "database", strlen("database"), "", ZEND_ACC_PUBLIC);
zend_declare_property_long(mysqli_ce, "port", strlen("port"), 3306, ZEND_ACC_PUBLIC);
zend_declare_property_string(mysqli_ce, "socket", strlen("socket"), "", ZEND_ACC_PUBLIC);
zend_declare_property_null(mysqli_ce, "errno", strlen("errno"), ZEND_ACC_PUBLIC);
zend_declare_property_string(mysqli_ce, "error", strlen("error"), "", ZEND_ACC_PUBLIC);
zend_declare_property_string(mysqli_ce, "sqlstate", strlen("sqlstate"), "00000", ZEND_ACC_PUBLIC);
zend_declare_property_long(mysqli_ce, "affected_rows", strlen("affected_rows"), 0, ZEND_ACC_PUBLIC);
zend_declare_property_long(mysqli_ce, "insert_id", strlen("insert_id"), 0, ZEND_ACC_PUBLIC);
zend_declare_property_string(mysqli_ce, "client_info", strlen("client_info"), "mysqli_polyfill", ZEND_ACC_PUBLIC);
zend_declare_property_long(mysqli_ce, "client_version", strlen("client_version"), 0, ZEND_ACC_PUBLIC);
zend_declare_property_string(mysqli_ce, "server_info", strlen("server_info"), "mysqli_polyfill", ZEND_ACC_PUBLIC);
zend_declare_property_long(mysqli_ce, "server_version", strlen("server_version"), 0, ZEND_ACC_PUBLIC);
zend_declare_property_string(mysqli_ce, "character_set_name", strlen("character_set_name"), "utf8", ZEND_ACC_PUBLIC);
zend_declare_property_string(mysqli_ce, "protocol_version", strlen("protocol_version"), "10", ZEND_ACC_PUBLIC);
zend_declare_property_long(mysqli_ce, "thread_id", strlen("thread_id"), 0, ZEND_ACC_PUBLIC);
zend_declare_property_long(mysqli_ce, "warning_count", strlen("warning_count"), 0, ZEND_ACC_PUBLIC);
zend_declare_property_null(mysqli_ce, "info", strlen("info"), ZEND_ACC_PUBLIC);
zend_declare_property_bool(mysqli_ce, "connect_errno", strlen("connect_errno"), 0, ZEND_ACC_PUBLIC);
zend_declare_property_string(mysqli_ce, "connect_error", strlen("connect_error"), "", ZEND_ACC_PUBLIC);

// Register constants
REGISTER_LONG_CONSTANT("MYSQLI_REPORT_OFF", MYSQLI_REPORT_OFF, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("MYSQLI_REPORT_ERROR", MYSQLI_REPORT_ERROR, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("MYSQLI_REPORT_STRICT", MYSQLI_REPORT_STRICT, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("MYSQLI_REPORT_INDEX", MYSQLI_REPORT_INDEX, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("MYSQLI_REPORT_ALL", MYSQLI_REPORT_ALL, CONST_CS | CONST_PERSISTENT);
return SUCCESS;
}
/* }}} */
Expand All @@ -40,7 +184,19 @@ PHP_MINFO_FUNCTION(mysqli_polyfill)

/* {{{ mysqli_polyfill_functions[] */
const zend_function_entry mysqli_polyfill_functions[] = {
ZEND_FE(mysqli_report, arginfo_mysqli_report){NULL, NULL, NULL}};
ZEND_FE(mysqli_report, arginfo_mysqli_report)
ZEND_FE(mysqli_get_server_info, arginfo_mysqli_get_server_info)
ZEND_FE(mysqli_init, arginfo_mysqli_init)
ZEND_FE(mysqli_connect, arginfo_mysqli_connect)
ZEND_FE(mysqli_real_connect, arginfo_mysqli_real_connect)
ZEND_FE(mysqli_query, arginfo_mysqli_query)
ZEND_FE(mysqli_fetch_array, arginfo_mysqli_fetch_array)
ZEND_FE(mysqli_select_db, arginfo_mysqli_select_db)
ZEND_FE(mysqli_close, arginfo_mysqli_close)
ZEND_FE(mysqli_real_escape_string, arginfo_mysqli_real_escape_string)
ZEND_FE(mysqli_errno, arginfo_mysqli_errno)
ZEND_FE(mysqli_error, arginfo_mysqli_error)
ZEND_FE_END};
/* }}} */

/* {{{ mysqli_polyfill_module_entry */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@
#ifndef MYSQLI_REPORT_INDEX
#define MYSQLI_REPORT_INDEX 4
#endif
#ifndef MYSQLI_REPORT_CLOSE
#define MYSQLI_REPORT_CLOSE 8
#endif
#ifndef MYSQLI_REPORT_ALL
#define MYSQLI_REPORT_ALL 255
#endif
Expand All @@ -30,6 +27,77 @@ ZEND_ARG_INFO(0, flags)
ZEND_END_ARG_INFO()
PHP_FUNCTION(mysqli_report);

ZEND_BEGIN_ARG_INFO_EX(arginfo_mysqli_init, 0, 0, 0)
ZEND_END_ARG_INFO()
PHP_FUNCTION(mysqli_init);

ZEND_BEGIN_ARG_INFO_EX(arginfo_mysqli_connect, 0, 0, 6)
ZEND_ARG_INFO(0, hostname)
ZEND_ARG_INFO(0, username)
ZEND_ARG_INFO(0, password)
ZEND_ARG_INFO(0, database)
ZEND_ARG_INFO(0, port)
ZEND_ARG_INFO(0, socket)
ZEND_END_ARG_INFO()
PHP_FUNCTION(mysqli_connect);

ZEND_BEGIN_ARG_INFO_EX(arginfo_mysqli_real_connect, 0, 0, 8)
ZEND_ARG_INFO(0, mysql)
ZEND_ARG_INFO(0, hostname)
ZEND_ARG_INFO(0, username)
ZEND_ARG_INFO(0, password)
ZEND_ARG_INFO(0, database)
ZEND_ARG_INFO(0, port)
ZEND_ARG_INFO(0, socket)
ZEND_ARG_INFO(0, flags)
ZEND_END_ARG_INFO()
PHP_FUNCTION(mysqli_real_connect);

ZEND_BEGIN_ARG_INFO_EX(arginfo_mysqli_get_server_info, 0, 0, 1)
ZEND_ARG_INFO(0, mysql)
ZEND_END_ARG_INFO()
PHP_FUNCTION(mysqli_get_server_info);

ZEND_BEGIN_ARG_INFO_EX(arginfo_mysqli_query, 0, 0, 3)
ZEND_ARG_INFO(0, mysql)
ZEND_ARG_INFO(0, query)
ZEND_ARG_INFO(0, result_mode)
ZEND_END_ARG_INFO()
PHP_FUNCTION(mysqli_query);

ZEND_BEGIN_ARG_INFO_EX(arginfo_mysqli_fetch_array, 0, 0, 2)
ZEND_ARG_INFO(0, result)
ZEND_ARG_INFO(0, mode)
ZEND_END_ARG_INFO()
PHP_FUNCTION(mysqli_fetch_array);

ZEND_BEGIN_ARG_INFO_EX(arginfo_mysqli_select_db, 0, 0, 2)
ZEND_ARG_INFO(0, mysql)
ZEND_ARG_INFO(0, database)
ZEND_END_ARG_INFO()
PHP_FUNCTION(mysqli_select_db);

ZEND_BEGIN_ARG_INFO_EX(arginfo_mysqli_close, 0, 0, 1)
ZEND_ARG_INFO(0, mysql)
ZEND_END_ARG_INFO()
PHP_FUNCTION(mysqli_close);

ZEND_BEGIN_ARG_INFO_EX(arginfo_mysqli_real_escape_string, 0, 0, 2)
ZEND_ARG_INFO(0, mysql)
ZEND_ARG_INFO(0, string)
ZEND_END_ARG_INFO()
PHP_FUNCTION(mysqli_real_escape_string);

ZEND_BEGIN_ARG_INFO_EX(arginfo_mysqli_errno, 0, 0, 1)
ZEND_ARG_INFO(0, mysql)
ZEND_END_ARG_INFO()
PHP_FUNCTION(mysqli_errno);

ZEND_BEGIN_ARG_INFO_EX(arginfo_mysqli_error, 0, 0, 1)
ZEND_ARG_INFO(0, mysql)
ZEND_END_ARG_INFO()
PHP_FUNCTION(mysqli_error);

#define PHP_MYSQLI_POLYFILL_VERSION "0.0.1"

#endif
33 changes: 32 additions & 1 deletion packages/php-wasm/node/src/test/php.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ destructive results fifty years hence. He was, I believe, not in the
least an ill-natured man: very much the opposite, I should say; but he
would not suffer fools gladly.`;

describe.each(SupportedPHPVersions)('PHP %s', (phpVersion) => {
describe.each(['8.0'])('PHP %s', (phpVersion) => {
let php: PHP;
beforeEach(async () => {
php = new PHP(await loadNodeRuntime(phpVersion as any));
Expand Down Expand Up @@ -198,6 +198,37 @@ describe.each(SupportedPHPVersions)('PHP %s', (phpVersion) => {
});
});

describe('mysql_report function()', () => {
it('MYSQLI report modes should exist', async () => {
const result = await php.run({
code: `<?php
echo json_encode(array(
'MYSQLI_REPORT_OFF' => MYSQLI_REPORT_OFF,
'MYSQLI_REPORT_ERROR' => MYSQLI_REPORT_ERROR,
'MYSQLI_REPORT_STRICT' => MYSQLI_REPORT_STRICT,
'MYSQLI_REPORT_INDEX' => MYSQLI_REPORT_INDEX,
'MYSQLI_REPORT_ALL' => MYSQLI_REPORT_ALL,
));
`,
});
expect(result.json).toEqual({
MYSQLI_REPORT_OFF: 0,
MYSQLI_REPORT_ERROR: 1,
MYSQLI_REPORT_STRICT: 2,
MYSQLI_REPORT_INDEX: 4,
MYSQLI_REPORT_ALL: 255,
});
});
it('mysql_report should exist and return true', async () => {
const result = await php.run({
code: `<?php
var_dump(mysqli_report(0));
`,
});
expect(result.text).toEqual('bool(true)\n');
});
});

describe('popen()', () => {
it('popen("echo", "r")', async () => {
const result = await php.run({
Expand Down
Binary file modified packages/php-wasm/web/public/php/asyncify/8_0_30/php_8_0.wasm
Binary file not shown.
2 changes: 1 addition & 1 deletion packages/php-wasm/web/public/php/asyncify/php_8_0.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit d740fea

Please sign in to comment.