SIGN IN SIGN UP
#ifndef _FRANKENPHP_H
#define _FRANKENPHP_H
2021-09-24 18:52:20 +02:00
feat: Windows support (#2119) Closes #83 #880 #1286. Working patch for Windows support. Supports linking to the [official PHP release (TS version)](https://www.php.net/downloads.php). Includes some work from #1286 (thanks @TenHian!!) This patch allows using Visual Studio to compile the cgo code. To do so, it must be compiled with Go 1.26 (RC) with the following setup: ```powershell winget install -e --id Microsoft.VisualStudio.2022.Community --override "--passive --wait --add Microsoft.VisualStudio.Workload.NativeDesktop --add Microsoft.VisualStudio.Component.VC.Llvm.Clang --includeRecommended" winget install -e --id GoLang.Go $env:PATH += ';C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\Llvm\bin' cd c:\ gh repo clone microsoft/vcpkg .\vcpkg\bootstrap-vcpkg.bat .\vcpkg\vcpkg install pthreads brotli # build watcher Invoke-WebRequest -Uri "https://github.com/e-dant/watcher/releases/download/0.14.3/x86_64-pc-windows-msvc.tar" -OutFile "$env:TEMP\watcher.tar" tar -xf "$env:TEMP\watcher.tar" -C C:\ Rename-Item -Path "C:\x86_64-pc-windows-msvc" -NewName "watcher-x86_64-pc-windows-msvc" Remove-Item "$env:TEMP\watcher.tar" # download php Invoke-WebRequest -Uri "https://downloads.php.net/~windows/releases/archives/php-8.5.1-Win32-vs17-x64.zip" -OutFile "$env:TEMP\php.zip" Expand-Archive -Path "$env:TEMP\php.zip" -DestinationPath "C:\" Remove-Item "$env:TEMP\php.zip" # download php development package Invoke-WebRequest -Uri "https://downloads.php.net/~windows/releases/archives/php-devel-pack-8.5.1-Win32-vs17-x64.zip" -OutFile "$env:TEMP\php-devel.zip" Expand-Archive -Path "$env:TEMP\php-devel.zip" -DestinationPath "C:\" Remove-Item "$env:TEMP\php-devel.zip" $env:GOTOOLCHAIN = 'go1.26rc1' $env:CC = 'clang' $env:CXX = 'clang++' $env:CGO_CFLAGS = "-I$env:C:\vcpkg\installed\x64-windows\include -IC:\watcher-x86_64-pc-windows-msvc -IC:\php-8.5.1-devel-vs17-x64\include -IC:\php-8.5.1-devel-vs17-x64\include\main -IC:\php-8.5.1-devel-vs17-x64\include\TSRM -IC:\php-8.5.1-devel-vs17-x64\include\Zend -IC:\php-8.5.1-devel-vs17-x64\include\ext" $env:CGO_LDFLAGS = '-LC:\vcpkg\installed\x64-windows\lib -lbrotlienc -LC:\watcher-x86_64-pc-windows-msvc -llibwatcher-c -LC:\php-8.5.1-Win32-vs17-x64 -LC:\php-8.5.1-devel-vs17-x64\lib -lphp8ts -lphp8embed' # clone frankenphp and build git clone -b windows https://github.com/php/frankenphp.git cd frankenphp\caddy\frankenphp go build -ldflags '-extldflags="-fuse-ld=lld"' -tags nowatcher,nobadger,nomysql,nopgx # Tests $env:PATH += ";$env:VCPKG_ROOT\installed\x64-windows\bin;C:\watcher-x86_64-pc-windows-msvc";C:\php-8.5.1-Win32-vs17-x64" "opcache.enable=0`r`nopcache.enable_cli=0" | Out-File -Encoding ascii php.ini $env:PHPRC = Get-Location go test -ldflags '-extldflags="-fuse-ld=lld"' -tags nowatcher,nobadger,nomysql,nopgx . ``` TODO: - [x] Fix remaining skipped tests (scaling and watcher) - [x] Test if the watcher mode works as expected - [x] Automate the build with GitHub Actions --------- Signed-off-by: Marc <m@pyc.ac> Co-authored-by: Kévin Dunglas <kevin@dunglas.dev> Co-authored-by: DubbleClick <m@pyc.ac>
2026-02-26 12:38:14 +01:00
#ifdef _WIN32
// Define this to prevent windows.h from including legacy winsock.h
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
// Explicitly include Winsock2 BEFORE windows.h
#include <windows.h>
#include <winerror.h>
#include <winsock2.h>
#include <ws2tcpip.h>
// Fix for missing IntSafe functions (LongLongAdd) when building with Clang
#ifdef __clang__
#ifndef INTSAFE_E_ARITHMETIC_OVERFLOW
#define INTSAFE_E_ARITHMETIC_OVERFLOW ((HRESULT)0x80070216L)
#endif
#ifndef LongLongAdd
static inline HRESULT LongLongAdd(LONGLONG llAugend, LONGLONG llAddend,
LONGLONG *pllResult) {
if (__builtin_add_overflow(llAugend, llAddend, pllResult)) {
return INTSAFE_E_ARITHMETIC_OVERFLOW;
}
return S_OK;
}
#endif
#ifndef LongLongSub
static inline HRESULT LongLongSub(LONGLONG llMinuend, LONGLONG llSubtrahend,
LONGLONG *pllResult) {
if (__builtin_sub_overflow(llMinuend, llSubtrahend, pllResult)) {
return INTSAFE_E_ARITHMETIC_OVERFLOW;
}
return S_OK;
}
#endif
#endif
#endif
#include <Zend/zend_modules.h>
#include <Zend/zend_types.h>
2023-12-01 17:26:21 +01:00
#include <stdbool.h>
#include <stdint.h>
2021-11-01 00:18:30 +01:00
2023-09-16 13:03:05 +02:00
#ifndef FRANKENPHP_VERSION
#define FRANKENPHP_VERSION dev
#endif
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
2024-01-22 13:23:37 +01:00
typedef struct go_string {
size_t len;
char *data;
2024-01-22 13:23:37 +01:00
} go_string;
typedef struct frankenphp_server_vars {
size_t total_num_vars;
char *remote_addr;
size_t remote_addr_len;
char *remote_host;
size_t remote_host_len;
char *remote_port;
size_t remote_port_len;
char *document_root;
size_t document_root_len;
char *path_info;
size_t path_info_len;
char *php_self;
size_t php_self_len;
char *document_uri;
size_t document_uri_len;
char *script_filename;
size_t script_filename_len;
char *script_name;
size_t script_name_len;
char *server_name;
size_t server_name_len;
char *server_port;
size_t server_port_len;
char *content_length;
size_t content_length_len;
char *server_protocol;
size_t server_protocol_len;
char *http_host;
size_t http_host_len;
char *request_uri;
size_t request_uri_len;
char *ssl_cipher;
size_t ssl_cipher_len;
zend_string *request_scheme;
zend_string *ssl_protocol;
zend_string *https;
} frankenphp_server_vars;
/**
* Cached interned strings for memory and performance benefits
* Add more hard-coded strings here if needed
*/
#define FRANKENPHP_INTERNED_STRINGS_LIST(X) \
X(remote_addr, "REMOTE_ADDR") \
X(remote_host, "REMOTE_HOST") \
X(remote_port, "REMOTE_PORT") \
X(document_root, "DOCUMENT_ROOT") \
X(path_info, "PATH_INFO") \
X(php_self, "PHP_SELF") \
X(document_uri, "DOCUMENT_URI") \
X(script_filename, "SCRIPT_FILENAME") \
X(script_name, "SCRIPT_NAME") \
X(https, "HTTPS") \
X(httpsLowercase, "https") \
X(httpLowercase, "http") \
X(ssl_protocol, "SSL_PROTOCOL") \
X(request_scheme, "REQUEST_SCHEME") \
X(server_name, "SERVER_NAME") \
X(server_port, "SERVER_PORT") \
X(content_length, "CONTENT_LENGTH") \
X(server_protocol, "SERVER_PROTOCOL") \
X(http_host, "HTTP_HOST") \
X(request_uri, "REQUEST_URI") \
X(ssl_cipher, "SSL_CIPHER") \
X(server_software, "SERVER_SOFTWARE") \
X(frankenphp, "FrankenPHP") \
X(gateway_interface, "GATEWAY_INTERFACE") \
X(cgi11, "CGI/1.1") \
X(auth_type, "AUTH_TYPE") \
X(remote_ident, "REMOTE_IDENT") \
X(content_type, "CONTENT_TYPE") \
X(path_translated, "PATH_TRANSLATED") \
X(query_string, "QUERY_STRING") \
X(remote_user, "REMOTE_USER") \
X(request_method, "REQUEST_METHOD") \
X(tls1, "TLSv1") \
X(tls11, "TLSv1.1") \
X(tls12, "TLSv1.2") \
X(tls13, "TLSv1.3") \
X(on, "on") \
X(empty, "")
typedef struct frankenphp_interned_strings_t {
#define F_DEFINE_STRUCT_FIELD(name, str) zend_string *name;
FRANKENPHP_INTERNED_STRINGS_LIST(F_DEFINE_STRUCT_FIELD)
#undef F_DEFINE_STRUCT_FIELD
} frankenphp_interned_strings_t;
extern frankenphp_interned_strings_t frankenphp_strings;
typedef struct frankenphp_version {
2023-12-01 17:26:21 +01:00
unsigned char major_version;
unsigned char minor_version;
unsigned char release_version;
const char *extra_version;
const char *version;
unsigned long version_id;
} frankenphp_version;
frankenphp_version frankenphp_get_version();
typedef struct frankenphp_config {
2023-12-01 17:26:21 +01:00
bool zts;
bool zend_signals;
bool zend_max_execution_timers;
} frankenphp_config;
frankenphp_config frankenphp_get_config();
2022-11-12 14:48:10 +01:00
refactor: decouple worker threads from non-worker threads (#1137) * Decouple workers. * Moves code to separate file. * Cleans up the exponential backoff. * Initial working implementation. * Refactors php threads to take callbacks. * Cleanup. * Cleanup. * Cleanup. * Cleanup. * Adjusts watcher logic. * Adjusts the watcher logic. * Fix opcache_reset race condition. * Fixing merge conflicts and formatting. * Prevents overlapping of TSRM reservation and script execution. * Adjustments as suggested by @dunglas. * Adds error assertions. * Adds comments. * Removes logs and explicitly compares to C.false. * Resets check. * Adds cast for safety. * Fixes waitgroup overflow. * Resolves waitgroup race condition on startup. * Moves worker request logic to worker.go. * Removes defer. * Removes call from go to c. * Fixes merge conflict. * Adds fibers test back in. * Refactors new thread loop approach. * Removes redundant check. * Adds compareAndSwap. * Refactor: removes global waitgroups and uses a 'thread state' abstraction instead. * Removes unnecessary method. * Updates comment. * Removes unnecessary booleans. * test * First state machine steps. * Splits threads. * Minimal working implementation with broken tests. * Fixes tests. * Refactoring. * Fixes merge conflicts. * Formatting * C formatting. * More cleanup. * Allows for clean state transitions. * Adds state tests. * Adds support for thread transitioning. * Fixes the testdata path. * Formatting. * Allows transitioning back to inactive state. * Fixes go linting. * Formatting. * Removes duplication. * Applies suggestions by @dunglas * Removes redundant check. * Locks the handler on restart. * Removes unnecessary log. * Changes Unpin() logic as suggested by @withinboredom * Adds suggestions by @dunglas and resolves TODO. * Makes restarts fully safe. * Will make the initial startup fail even if the watcher is enabled (as is currently the case) * Also adds compareAndSwap to the test. * Adds comment. * Prevents panic on initial watcher startup.
2024-12-17 11:28:51 +01:00
int frankenphp_new_main_thread(int num_threads);
bool frankenphp_new_php_thread(uintptr_t thread_index);
bool frankenphp_shutdown_dummy_request(void);
int frankenphp_execute_script(char *file_name);
void frankenphp_update_local_thread_context(bool is_worker);
2021-09-24 18:52:20 +02:00
2025-05-01 02:06:31 +02:00
int frankenphp_execute_script_cli(char *script, int argc, char **argv,
bool eval);
void frankenphp_register_known_variable(zend_string *z_key, char *value,
size_t val_len, zval *track_vars_array);
void frankenphp_register_variable_safe(char *key, char *var, size_t val_len,
zval *track_vars_array);
void frankenphp_register_server_vars(zval *track_vars_array,
frankenphp_server_vars vars);
zend_string *frankenphp_init_persistent_string(const char *string, size_t len);
int frankenphp_reset_opcache(void);
int frankenphp_get_current_memory_limit();
void register_extensions(zend_module_entry **m, int len);
2021-09-24 18:52:20 +02:00
#endif