使用自定义PHP模块,为什么不填充$ _POST?

时间:2016-10-30 21:32:43

标签: php macos post php-internals

我在PHP 5.6.27上编译了macOS 10.12.1 Sierra作为静态库(本身就是一个小壮举)。我已将我的应用程序链接到所有必需的库,它正在构建而没有错误。使用静态PHP库,我可以执行任意PHP代码并执行PHP脚本。但是,如果我尝试使用表单数据处理脚本(从同一应用程序中的嵌入式HTTP服务器检索),则永远不会填充$_POST全局(如果请求,$_GET全局设置正常是GET,其中包含URL中的查询字符串。

不包括整个项目,这里是我的PHP处理器类,带有我的自定义PHP模块和用于在没有实际HTTP请求的情况下测试处理器的存根,但是具有相同内容的请求将生成我的类所需的。您可以在底部看到,在截断的结果中,运行PHP脚本并调用read_post方法并正确加载提供的缓冲区,然后PHP应该使用该缓冲区来填充$_POST数组,但{{1}数组保持为空(虽然已初始化)。任何提示都将非常受欢迎。

PHPProcessor.h:

$_POST

PHPProcessor.m:

#import <Cocoa/Cocoa.h>

@interface PHPProcessor : NSObject
@property (strong) NSString *requestMethod;
@property (strong) NSURL *requestURL;
@property (strong) NSString *requestContentType;
@property (strong) NSData *bodyData;
@property (readonly) NSString *resultString;
+ (instancetype)phpProcessor;
- (BOOL)executeScript:(NSString *)filepath;
@end

test.php的:

#import "PHPProcessor.h"
#include "php.h"
#include "php_main.h"
#include "php_variables.h"

@interface PHPProcessor ()
@property (assign) NSInteger bodyDataOffset;
@property (strong) NSString *resultString;
@end

static int phpp_startup(sapi_module_struct *sapi_module) {
    return ((php_module_startup(sapi_module, NULL, 0) == FAILURE) ? FAILURE : SUCCESS);
}

static int phpp_shutdown(sapi_module_struct *sapi_module) {
    return ((php_module_shutdown_wrapper(sapi_module) == FAILURE) ? FAILURE : SUCCESS);
}

static int phpp_ub_write(const char *str, unsigned int str_length TSRMLS_DC) {
    PHPProcessor *phpProcessor = (__bridge PHPProcessor *)SG(server_context);
    NSString *newString = [NSString stringWithUTF8String:str];
    if (!newString) newString = [NSString stringWithCString:str encoding:NSASCIIStringEncoding];
    if (newString) {
        NSString *resultString = phpProcessor.resultString;
        if (!resultString) resultString = [NSString string];
        resultString = [resultString stringByAppendingString:newString];
        phpProcessor.resultString = resultString;
        return str_length;
    }
    return 0;
}

static int phpp_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC) {
    return SAPI_HEADER_SENT_SUCCESSFULLY;
}

static int phpp_read_post(char *buffer, uint count_bytes TSRMLS_DC) {
    PHPProcessor *phpProcessor = (__bridge PHPProcessor *)SG(server_context);
    NSData *bodyData = phpProcessor.bodyData;
    uint remaining_bytes = (uint)(bodyData.length - phpProcessor.bodyDataOffset);
    count_bytes = MIN(count_bytes, remaining_bytes);
    [bodyData getBytes:buffer range:NSMakeRange(phpProcessor.bodyDataOffset, count_bytes)];
    phpProcessor.bodyDataOffset += count_bytes;
#if DEBUG
    NSLog(@"verifying buffer from read_post: %@", [[NSString alloc] initWithBytes:buffer length:phpProcessor.bodyDataOffset encoding:NSASCIIStringEncoding]);
#endif
    return count_bytes;
}

static void phpp_register_variable(int arg, zval *track_vars_array, const char *key, const char *val TSRMLS_DC) {
    char *new_val = (char *)val; uint new_val_len;
    if (val && sapi_module.input_filter(arg, (char *)key, &new_val, (unsigned int)strlen(val), &new_val_len TSRMLS_CC)) php_register_variable_safe((char *)key, new_val, new_val_len, track_vars_array TSRMLS_CC);
}

static void phpp_register_server_variables(zval *track_vars_array TSRMLS_DC) {
    phpp_register_variable(PARSE_SERVER, track_vars_array, "SERVER_SOFTWARE", [[[NSBundle mainBundle] objectForInfoDictionaryKey:(id)kCFBundleNameKey] UTF8String]);
}

static void phpp_log_message(char *message TSRMLS_DC) {
    printf("%s\n", message);
}

sapi_module_struct phpp_module = {
    "phpp",                     // char *name;
    "PHP Processor Module",         // char *pretty_name;
    phpp_startup,                   // int (*startup)(struct _sapi_module_struct *sapi_module);
    phpp_shutdown,                  // int (*shutdown)(struct _sapi_module_struct *sapi_module);
    NULL,                       // int (*activate)(TSRMLS_D);
    NULL,                       // int (*deactivate)(TSRMLS_D);
    phpp_ub_write,                  // int (*ub_write)(const char *str, unsigned int str_length TSRMLS_DC);
    NULL,                       // void (*flush)(void *server_context);
    NULL,                       // struct stat *(*get_stat)(TSRMLS_D);
    NULL,                       // char *(*getenv)(char *name, size_t name_len TSRMLS_DC);
    NULL,                       // void (*sapi_error)(int type, const char *error_msg, ...);
    NULL,                       // int (*header_handler)(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers TSRMLS_DC);
    phpp_send_headers,              // int (*send_headers)(sapi_headers_struct *sapi_headers TSRMLS_DC);
    NULL,                       // void (*send_header)(sapi_header_struct *sapi_header, void *server_context TSRMLS_DC);
    phpp_read_post,             // int (*read_post)(char *buffer, uint count_bytes TSRMLS_DC);
    NULL,                       // char *(*read_cookies)(TSRMLS_D);
    phpp_register_server_variables, // void (*register_server_variables)(zval *track_vars_array TSRMLS_DC);
    phpp_log_message,               // void (*log_message)(char *message TSRMLS_DC);
    NULL,                       // double (*get_request_time)(TSRMLS_D);
    NULL,                       // void (*terminate_process)(TSRMLS_D);
    "",                         // char *php_ini_path_override; // "" causes $_ENV to be set
    STANDARD_SAPI_MODULE_PROPERTIES
};

@implementation PHPProcessor

+ (void)initialize {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sapi_module_struct *sapi_module = &phpp_module;
        sapi_startup(sapi_module);
        sapi_module->startup(sapi_module);
    });
}

+ (instancetype)phpProcessor { return [self new]; }

- (instancetype)init {
    if (self = [super init]) {
    }
    return self;
}

- (BOOL)executeScript:(NSString *)filepath {
    self.resultString = nil;
    self.bodyDataOffset = 0;
    SG(request_info).request_method = (char *)self.requestMethod.UTF8String;
    SG(request_info).content_type = (char *)self.requestContentType.UTF8String;
    SG(request_info).content_length = (long)self.bodyData.length;
    SG(request_info).request_uri = (char *)self.requestURL.relativePath.UTF8String;
    SG(request_info).path_translated = (char *)filepath.UTF8String;
    SG(request_info).query_string = (char *)self.requestURL.query.UTF8String;
    if (php_request_startup(TSRMLS_C) == SUCCESS) {
        SG(server_context) = (void *)CFBridgingRetain(self);
        zend_file_handle file_handle;
        file_handle.type = ZEND_HANDLE_FILENAME;
        file_handle.filename = filepath.UTF8String;
        file_handle.free_filename = 0;
        file_handle.opened_path = NULL;
        php_execute_script(&file_handle TSRMLS_CC);
        php_request_shutdown(NULL);
        SG(server_context) = NULL;
        CFRelease(self);
        return YES;
    }
    return NO;
}

@end

使用PHPProcessor的代码:

<?php
echo("<pre>\n");
echo("GET: ");
print_r($_GET);
echo("POST: ");
print_r($_POST);
echo("SERVER: ");
print_r($_SERVER);
echo("ENV: ");
print_r($_ENV);
echo("</pre>\n");
phpinfo();
?>

结果:

NSString *filepath = @"~/Desktop/test.php".stringByExpandingTildeInPath;
PHPProcessor *phpProcessor = [PHPProcessor phpProcessor];
phpProcessor.requestMethod = @"POST";
phpProcessor.requestURL = [NSURL fileURLWithPath:filepath];
phpProcessor.requestContentType = @"application/x-www-form-urlencoded";
phpProcessor.bodyData = [@"a=123&b=456" dataUsingEncoding:NSUTF8StringEncoding];
[phpProcessor executeScript:filepath];
NSLog(@"resultString:\n\n%@", phpProcessor.resultString);

1 个答案:

答案 0 :(得分:1)

对于那些对解决方案感兴趣的人,基本上归结为将.AddRemainingFields() 启动移到类sapi_module_struct方法之外并从实例方法调用它。我还清理了其余的代码,由于某种原因,为了避免崩溃,我不得不添加一个读取cookie的函数,即使我最初并不感兴趣(返回一个有效的cookie字符串确实initialization数组)。希望这可以帮助其他人。

修改了PHPProcessor.m:

$_COOKIE

<强>结果:

#import "PHPProcessor.h"
#include "php.h"
#include "php_main.h"
#include "php_variables.h"

@interface PHPProcessor ()
@property (assign) NSInteger bodyDataOffset;
@property (strong) NSMutableString *mutableResultString;
@end

static int phpp_startup(sapi_module_struct *sapi_module) {
    return ((php_module_startup(sapi_module, NULL, 0) == FAILURE) ? FAILURE : SUCCESS);
}

static int phpp_shutdown(sapi_module_struct *sapi_module) {
    return ((php_module_shutdown_wrapper(sapi_module) == FAILURE) ? FAILURE : SUCCESS);
}

static int phpp_ub_write(const char *str, unsigned int str_length TSRMLS_DC) {
    PHPProcessor *phpProcessor = (__bridge PHPProcessor *)SG(server_context);
    NSString *newString = [NSString stringWithUTF8String:str];
    if (!newString) newString = [NSString stringWithCString:str encoding:NSASCIIStringEncoding];
    if (newString) {
        [phpProcessor.mutableResultString appendString:newString];
        return str_length;
    }
    return 0;
}

static int phpp_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC) {
    return SAPI_HEADER_SENT_SUCCESSFULLY;
}

static int phpp_read_post(char *buffer, uint count_bytes TSRMLS_DC) {
    PHPProcessor *phpProcessor = (__bridge PHPProcessor *)SG(server_context);
    NSData *bodyData = phpProcessor.bodyData;
    uint remaining_bytes = (uint)(bodyData.length - phpProcessor.bodyDataOffset);
    count_bytes = MIN(count_bytes, remaining_bytes);
    [bodyData getBytes:buffer range:NSMakeRange(phpProcessor.bodyDataOffset, count_bytes)];
    phpProcessor.bodyDataOffset += count_bytes;
#if DEBUG
    NSLog(@"verifying buffer from read_post: %@", [[NSString alloc] initWithBytes:buffer length:phpProcessor.bodyDataOffset encoding:NSASCIIStringEncoding]);
#endif
    return count_bytes;
}

static char *phpp_read_cookies(TSRMLS_D) {
    return NULL;
}

static void phpp_register_variable(int arg, zval *track_vars_array, const char *key, const char *val TSRMLS_DC) {
    char *new_val = (char *)val; uint new_val_len;
    if (val && sapi_module.input_filter(arg, (char *)key, &new_val, (unsigned int)strlen(val), &new_val_len TSRMLS_CC)) php_register_variable_safe((char *)key, new_val, new_val_len, track_vars_array TSRMLS_CC);
}

static void phpp_register_server_variables(zval *track_vars_array TSRMLS_DC) {
    phpp_register_variable(PARSE_SERVER, track_vars_array, "SERVER_SOFTWARE", [[[NSBundle mainBundle] objectForInfoDictionaryKey:(id)kCFBundleNameKey] UTF8String]);
}

static void phpp_log_message(char *message TSRMLS_DC) {
    printf("%s\n", message);
}

sapi_module_struct phpp_module = {
    "phpp",                     // char *name;
    "PHP Processor Module",         // char *pretty_name;
    phpp_startup,                   // int (*startup)(struct _sapi_module_struct *sapi_module);
    phpp_shutdown,                  // int (*shutdown)(struct _sapi_module_struct *sapi_module);
    NULL,                       // int (*activate)(TSRMLS_D);
    NULL,                       // int (*deactivate)(TSRMLS_D);
    phpp_ub_write,                  // int (*ub_write)(const char *str, unsigned int str_length TSRMLS_DC);
    NULL,                       // void (*flush)(void *server_context);
    NULL,                       // struct stat *(*get_stat)(TSRMLS_D);
    NULL,                       // char *(*getenv)(char *name, size_t name_len TSRMLS_DC);
    php_error,                  // void (*sapi_error)(int type, const char *error_msg, ...);
    NULL,                       // int (*header_handler)(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers TSRMLS_DC);
    phpp_send_headers,              // int (*send_headers)(sapi_headers_struct *sapi_headers TSRMLS_DC);
    NULL,                       // void (*send_header)(sapi_header_struct *sapi_header, void *server_context TSRMLS_DC);
    phpp_read_post,             // int (*read_post)(char *buffer, uint count_bytes TSRMLS_DC);
    phpp_read_cookies,              // char *(*read_cookies)(TSRMLS_D);
    phpp_register_server_variables, // void (*register_server_variables)(zval *track_vars_array TSRMLS_DC);
    phpp_log_message,               // void (*log_message)(char *message TSRMLS_DC);
    NULL,                       // double (*get_request_time)(TSRMLS_D);
    NULL,                       // void (*terminate_process)(TSRMLS_D);
    "",                         // char *php_ini_path_override; // "" causes $_ENV to be set
    STANDARD_SAPI_MODULE_PROPERTIES
};

@implementation PHPProcessor

+ (void)initialize {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sapi_startup(&phpp_module);
    });
}

+ (instancetype)phpProcessor { return [self new]; }

- (instancetype)init {
    if (self = [super init]) {
    }
    return self;
}

- (void)shutdownModule {
    SG(server_context) = NULL;
    CFRelease(self);
    php_module_shutdown(TSRMLS_C);
}

- (BOOL)executeScript:(NSString *)filepath {
    self.bodyDataOffset = 0;
    self.mutableResultString = [NSMutableString string];
    if (phpp_module.startup(&phpp_module) == FAILURE) return NO;
    int exit_status = FAILURE;
    zend_first_try {
        SG(server_context) = (void *)CFBridgingRetain(self);
        SG(request_info).request_method = (char *)self.requestMethod.UTF8String;
        SG(request_info).content_type = (char *)self.requestContentType.UTF8String;
        SG(request_info).content_length = (long)self.bodyData.length;
        SG(request_info).request_uri = (char *)self.requestURL.relativePath.UTF8String;
        SG(request_info).path_translated = (char *)filepath.fileSystemRepresentation;
        SG(request_info).query_string = (char *)self.requestURL.query.UTF8String;
        char *argv[2] = {phpp_module.name, NULL};
        SG(request_info).argc = 1;
        SG(request_info).argv = argv;
        SG(request_info).argv0 = phpp_module.name;
        SG(sapi_headers).http_response_code = 200;
        if (php_request_startup(TSRMLS_C) == FAILURE) {
            [self shutdownModule];
            return NO;
        }
        if (SG(request_info).path_translated) {
            zend_file_handle file_handle;
            file_handle.type = ZEND_HANDLE_FILENAME;
            file_handle.filename = SG(request_info).path_translated;
            file_handle.free_filename = 0;
            file_handle.opened_path = NULL;
            if (php_fopen_primary_script(&file_handle TSRMLS_CC) == FAILURE) {
                zend_try {
                    if (errno == EACCES) {
                        SG(sapi_headers).http_response_code = 403;
                        self.mutableResultString = [NSMutableString stringWithString:@"Access denied."];
                    } else {
                        SG(sapi_headers).http_response_code = 404;
                        self.mutableResultString = [NSMutableString stringWithString:@"No input file specified."];
                    }
                } zend_catch {
                } zend_end_try();
                STR_FREE(SG(request_info).path_translated);
                php_request_shutdown((void *)0);
                [self shutdownModule];
                return NO;
            }
            php_execute_script(&file_handle TSRMLS_CC);
            exit_status = SUCCESS;
        }
    } zend_catch {
    } zend_end_try();
    [self shutdownModule];
    return (exit_status == SUCCESS);
}

- (NSString *)resultString { return [NSString stringWithString:self.mutableResultString]; }

@end