用Php扩展实现的简单框架 - 5

来源:互联网 发布:中国单挑全世界知乎 编辑:程序博客网 时间:2024/06/05 18:51
php_inner.c: (代码太长,后半部分)


/** k_len可为0。 */
static inline zval * kiss_get_cache_obj(char * key, uint k_len TSRMLS_DC) {
    zval ** obj;

    if(!key) return NULL;
    if(!k_len) k_len = strlen(key);

    if(SUCCESS==zend_hash_find(Z_ARRVAL_P(KISS_G(obj_cache)), key, k_len+1, (void**)&obj)) {
     return *obj;
    }
    return NULL;
}

static inline void kiss_set_cache_obj(char * key, zval * obj TSRMLS_DC) {
    if(!key) return;
    add_assoc_zval(KISS_G(obj_cache), key, obj);
}

static inline zend_bool kiss_is_ls_called(char * ls, ulong type TSRMLS_DC) {
    char * key;
    uint k_len;
    zend_bool ret;
    if(!ls) return 0;
    k_len = spprintf(&key, 0, "%s->%s", ls, ls_func_name(type));
    ret = zend_hash_exists(Z_ARRVAL_P(KISS_G(ls_called)), key, k_len+1);
    efree(key);
    return ret;
}

static inline void kiss_set_ls_called(char * ls, ulong type TSRMLS_DC) {
    char * key;
    if(!ls) return;
    spprintf(&key, 0, "%s->%s", ls, ls_func_name(type));
    add_assoc_long(KISS_G(ls_called), key, 1);
    efree(key);
}

/** 根据[模块名和]控制器合成控制器类名。
 * 控制器为空则返回0。 */

static uint kiss_make_class_name(char * mdl, char * ctl, char ** cls_name TSRMLS_DC) {
    char fm, fc;
    uint cls_len;
    kiss_status * status = KISS_G(status);

    if(!ctl || '/0'==*ctl) return 0;
    fc = ctl[0];
    if('a' <= fc && 'z' >= fc) fc -= 32;

    if(!status->prefix_ctl || !mdl || '/0'==*mdl) { // 不使用模块作为类名前缀(或缺省模块)

        cls_len = spprintf(cls_name, 0, "%c%s%s", fc, ctl+1, status->postfix_ctl);
    } else {
        fm = mdl[0];
        if('a' <= fm && 'z' >= fm) fm -= 32;
        cls_len = spprintf(cls_name, 0, "%c%s%c%s%s", fm, mdl+1, fc, ctl+1, status->postfix_ctl);
    }
    return cls_len;
}

/** 根据[控制器路径和]控制器合成控制器类名。
 * 控制器为空则返回NULL。
 * TODO: ctl_dir为空时使用DOC_ROOT或缺省模块路径? */

static char * kiss_make_class_file(char * ctl_dir, char * ctl TSRMLS_DC) {
    char fc, * cls_file;
    kiss_status * status = KISS_G(status);

    if(!ctl || '/0'==*ctl) return NULL;
    fc = ctl[0];
    if('a' <= fc && 'z' >= fc) fc -= 32;
    if(!ctl_dir || '/0'==*ctl_dir) {
        spprintf(&cls_file, 0, "%c%s%s%s", fc, ctl+1, status->postfix_ctl, status->ext_proc);
    } else {
        spprintf(&cls_file, 0, "%s%c%s%s%s", ctl_dir, fc, ctl+1, status->postfix_ctl, status->ext_proc);
    }

    return cls_file;
}

/** NULL或""参数,或文件不存在或不可读则返回0。
 * TODO: 加强文件读取部分(error, eof, empty line ...)。 */

static zend_bool kiss_init_cfg(char * cfg_file TSRMLS_DC) {
    FILE * stream;
    char key[1024], value[1024], dir_sep;
    uint k_len, v_len;
    kiss_rule * rule;
    // char line[1024];


    if(!cfg_file || '/0'==*cfg_file) return 0;
    stream = fopen(cfg_file, "r");
    if(!stream) return 0;
    dir_sep = KISS_G(dir_sep);

    while(!feof(stream)) {
        // fread(line, 1, 1024, stream);

        if(EOF == fscanf(stream, "%s %s", key, value)) continue;
        if(ferror(stream)) { break; }
        k_len = strlen(key) - 1;
        while(k_len>0 && key[k_len] == PATH_SEP) k_len--;
        key[++k_len] = '/0';
        v_len = strlen(value);
        if(value[v_len-1] != dir_sep) {
            value[v_len] = dir_sep;
            value[++v_len] = '/0';
        }
        if(!strncmp(key, LS_PREFIX, 2)) {
            zend_hash_update(&KISS_G(hosts_ls), key, k_len+1,
                (void *)pestrdup(value, 1), v_len+1, NULL);
            continue;
        } else if(!strncmp(key, RW_PREFIX, 2)) {
            rule = kiss_make_rule_value(value, v_len);
            if(!rule) continue;
            zend_hash_update(&KISS_G(hosts_rw), key, k_len+1,
                (void *)rule, sizeof(kiss_rule), NULL);
            efree(rule);
        }
    }
    fclose(stream);

    KISS_G(cfg_inited) = 1;
    return 1;
}

/** 分层的路由器,也解析uri中的查询参数。返回值:是否匹配URI。 */
static zend_bool kiss_route_layer(char * path TSRMLS_DC) {
    kiss_request * req;
    kiss_status * status;
    char * domain, * p1, * p2, * prev=NULL, * key=NULL, * rule_key;
    uint dm_len, p1_len, rule_key_len, ep_len;

    if(!path || '/0'==*path) return 0;

    req = KISS_G(request);
    status = KISS_G(status);
    domain = req->host;
    dm_len = strlen(domain);

    p1_len = strlen(path);
    if(status->ext_path) { // 过滤

        ep_len = strlen(status->ext_path);
        if(strcmp(path+p1_len-ep_len, status->ext_path))
            return 0;
        else
            p1_len -= ep_len;
    }
    p1 = (char*)emalloc(p1_len+2);
    if(!p1) return 0;
    strncpy(p1, path, p1_len);
    *(p1 + p1_len) = '/';
    *(p1 + p1_len + 1) = '/0';
    p2 = p1;
    while(*p2) {
        if('/' != *p2) {
            if(!prev) prev = p2;
        } else {
            *p2 = '/0';
            if(prev) {
                if(!req->module) { // 模块优先于缺省模块中的同名控制器

                    rule_key_len = spprintf(&rule_key, 0, RW_PREFIX ":%s/%s", domain, prev);
                    if(!zend_hash_exists(&KISS_G(hosts_rw), rule_key, rule_key_len+1)) {
                        efree(p1);
                        efree(rule_key);
                        return 0;
                    }
                    req->module = estrdup(prev);
                    efree(rule_key);
                } else if(!req->controller) {
                    req->controller = estrdup(prev);
                } else if(!req->action) {
                    req->action = estrdup(prev);
                } else {
                    if(key) {
                        add_assoc_string(req->query, key, prev, 1);
                        key = NULL;
                    } else {
                        key = prev;
                    }
                }
                prev = NULL;
            }
        }
        p2 ++;
    }
    if(key) {
        add_assoc_string(req->query, key, "", 1);
        key = NULL;
    }
    if(!req->module) req->module = estrdup(status->default_mdl);
    if(!req->controller) req->controller = estrdup(status->default_ctl);
    if(!req->action) req->action = estrdup(status->default_act);
    efree(p1);
    
    return 1;
}

/** 分发器:对象方法(默认)或函数(过程)。 */
static inline zend_bool kiss_dispatch(TSRMLS_D) {
    // if(KISS_DISPATCH_METHOD == KISS_G(dispatch_type))

    if(KISS_DISPATCH_METHOD == KISS_G(status)->dispatch_type)
        return kiss_dispatch_method(TSRMLS_C);
    else
        return kiss_dispatch_function(TSRMLS_C);
}

/** 对象方法分发器。
 * 可能抛出异常(类文件或类无效)。 */

static zend_bool kiss_dispatch_method(TSRMLS_D) {
    char * ctl_file, * func_name, * cls_name, * rule_key, * ctl_dir, * ctl_dir_abs;
    uint rule_key_len, cls_len;
    zend_bool flag;
    zval * ctl, * func, * ret, * ins;
    kiss_request * req;
    kiss_rule * rule;

    req = KISS_G(request);
    cls_len = kiss_make_class_name(req->module, req->controller, &cls_name TSRMLS_CC);
    if(!cls_len) return 0;

    ins = kiss_get_cache_obj(cls_name, cls_len TSRMLS_CC);

    if(!ins) {
        rule_key_len = spprintf(&rule_key, 0, RW_PREFIX ":%s/%s", req->host, req->module);
        if(zend_hash_find(&KISS_G(hosts_rw), rule_key, rule_key_len+1, (void**)&rule) == FAILURE) {
            efree(rule_key);

            efree(cls_name);
            return 0;
        }
        ctl_dir = rule->controller_dir;
        efree(rule_key);

        if(!kiss_class_exists(cls_name TSRMLS_CC)) {
            if(kiss_absolute_path(ctl_dir, &ctl_dir_abs TSRMLS_CC)) {
                ctl_file = kiss_make_class_file(ctl_dir, req->controller TSRMLS_CC);
            } else {
                ctl_file = kiss_make_class_file(ctl_dir_abs, req->controller TSRMLS_CC);
                efree(ctl_dir_abs);
            }
            if(!ctl_file) { efree(cls_name); return 0; }
            MAKE_STD_ZVAL(ctl);
            ZVAL_STRING(ctl, ctl_file, 0);
            flag = kiss_eval(KISS_REQUIRE_ONCE, ctl, NULL TSRMLS_CC);
            // efree(ctl_file);

            zval_ptr_dtor(&ctl);
            if(!flag) {
                zend_throw_exception_ex(NULL, KISS_E_CLSFILE TSRMLS_CC, "找不到类<b>%s</b>的定义文件!", cls_name);
                efree(cls_name);
                return 0;
            }
        }

        ins = kiss_create_object(cls_name TSRMLS_CC);
        if(!ins || !IS_ZEND_STD_OBJECT(*ins)
        #ifndef PHP_WIN32
            || !instanceof_function(Z_OBJCE_P(ins), KISS_G(action_ce) TSRMLS_CC)
        #endif
        ) {
            zend_throw_exception_ex(NULL, KISS_E_INSTANCE TSRMLS_CC, "未能正确创建类%s的实例!", cls_name);

            efree(cls_name);
            if(ins) zval_ptr_dtor(&ins);
            return 0;
        }
        kiss_set_cache_obj(cls_name, ins TSRMLS_CC);
/*
        MAKE_STD_ZVAL(func);
        MAKE_STD_ZVAL(ret);

        ZVAL_STRING(func, KISS_ACTION_INIT_FUNC, 0);
        if(FAILURE == kiss_call_user_function(NULL, &ins, func, ret, 0, NULL TSRMLS_CC)) {
         zend_throw_exception_ex(NULL, KISS_E_CALLMTD TSRMLS_CC,
         "调用方法%s::" KISS_ACTION_INIT_FUNC "()失败!", cls_name);
            zval_ptr_dtor(&ret);
            efree(func);
            efree(cls_name);
            return 0;
        }
    } else {
        MAKE_STD_ZVAL(func);
        MAKE_STD_ZVAL(ret);
    }
*/

    }
    MAKE_STD_ZVAL(func);
    MAKE_STD_ZVAL(ret);

    if(!kiss_ls_dispatch(KISS_LS_PRE_DISPATCH TSRMLS_CC)) {
        //zval_ptr_dtor(&func); // 有内存泄露

        zval_ptr_dtor(&ret);
        efree(func); // func为zval*,但其strval非拷贝的,不可用zval_ptr_dtor()。

        efree(cls_name);
        return 0;
    }


    spprintf(&func_name, 0, "%s%s", req->action, KISS_G(status)->postfix_act);
    ZVAL_STRING(func, func_name, 0);
    if(FAILURE == kiss_call_user_function(NULL, &ins, func, ret, 0, NULL TSRMLS_CC)) {
        zend_throw_exception_ex(NULL, KISS_E_CALLMTD TSRMLS_CC, "调用方法%s::%s()失败!", cls_name, func_name);
        zval_ptr_dtor(&ret);
        efree(func); // func为zval*,但其strval非拷贝的,不可用zval_ptr_dtor()。

        efree(cls_name);
        return 0;
    }

    efree(cls_name);
    // zval_ptr_dtor(&ins);

    // efree(func_name);

    zval_ptr_dtor(&func);
    zval_ptr_dtor(&ret);
    
    if(!kiss_ls_dispatch(KISS_LS_POST_DISPATCH TSRMLS_CC)) return 0;

    return 1;
}

/** 函数分发器。TODO: 修正、完善。 */
static zend_bool kiss_dispatch_function(TSRMLS_D) {
    zval * ctl, * func, * ret;
    char * root, * ctl_file, * func_name, * rule_key, * ctl_dir;
    uint rule_key_len;
    kiss_request * req;
    kiss_rule * rule;
    
    req = KISS_G(request);

    rule_key_len = spprintf(&rule_key, 0, RW_PREFIX ":%s/%s", req->host, req->module);
    if(zend_hash_find(&KISS_G(hosts_rw), rule_key, rule_key_len+1, (void**)&rule) == FAILURE) {
        efree(rule_key);
        return 0;
    }
    ctl_dir = rule->controller_dir;
    efree(rule_key);

    if(IS_ABSOLUTE_PATH(ctl_dir, strlen(ctl_dir))) {
        spprintf(&ctl_file, 0, "%s%s" PHP_EXT, ctl_dir, req->controller);
    } else {
        root = zend_getenv(DOC_ROOT, DOC_ROOT_LEN TSRMLS_CC);
        if(!root || '/0'==*root) root = KISS_G(status)->cli_root;
        if(root) spprintf(&ctl_file, 0, "%s%s%s%s" PHP_EXT, root, KISS_G(dir_sep), ctl_dir, req->controller);
        spprintf(&ctl_file, 0, "%s%c%s%s" PHP_EXT, root, KISS_G(dir_sep), ctl_dir, req->controller);
    }

    MAKE_STD_ZVAL(ctl);
    ZVAL_STRING(ctl, ctl_file, 0);
    kiss_eval(KISS_REQUIRE_ONCE, ctl, NULL TSRMLS_CC);
    // 无文件则报错,需要抑制,以避免显示目录结构。


    MAKE_STD_ZVAL(func);
    spprintf(&func_name, 0, "%s" ACTION_EXT, req->action);
    ZVAL_STRING(func, func_name, 0);
    MAKE_STD_ZVAL(ret);
    if(FAILURE == kiss_call_user_function(EG(function_table), NULL, func, ret, 0, NULL TSRMLS_CC)) {
    //如何区分不同控制器中的同名函数???

        php_printf("failure to call function: %s<br/>/n", req->action);
    }

    // efree(ctl_file);

    zval_ptr_dtor(&ctl);
    // efree(func_name);

    zval_ptr_dtor(&func);
    zval_ptr_dtor(&ret);
    return 1;
}

/** TODO: 整理代码。
 * 可能抛出异常(类文件或类无效)。 */

static zend_bool kiss_ls_dispatch(ulong type TSRMLS_DC) {
    char * ls_key, * ls_dir = NULL, * ls_dir_abs = NULL, * ls, * ls_file;

    char * func_name;
    uint ls_key_len, ls_size, ls_file_len;
    zend_bool flag, exe_flag = 1;
    zval * lss, * ls_file2, * disp_func, * ret, * ls_ins;
    kiss_request * req;
    kiss_status * status;
    HashPosition pos_ht;
    
    req = KISS_G(request);
    status = KISS_G(status);

    func_name = ls_func_name(type);

    ls_key_len = spprintf(&ls_key, 0, LS_PREFIX ":%s", req->host);
    if(zend_hash_find(&KISS_G(hosts_ls), ls_key, ls_key_len+1, (void**)&ls_dir)==SUCCESS) {
        lss = kiss_get_listeners(type TSRMLS_CC);

        if(lss && zend_hash_num_elements(Z_ARRVAL_P(lss))) {
            if(!kiss_absolute_path(ls_dir, &ls_dir_abs TSRMLS_CC)) ls_dir = ls_dir_abs;
     for(zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(lss), &pos_ht);
     zend_hash_get_current_key_ex(Z_ARRVAL_P(lss), &ls, &ls_size,
     NULL, 0, &pos_ht)==HASH_KEY_IS_STRING;
     zend_hash_move_forward_ex(Z_ARRVAL_P(lss), &pos_ht)) {

                if(kiss_is_ls_called(ls, type TSRMLS_CC)) continue;
                ls_ins = kiss_get_cache_obj(ls, ls_size-1 TSRMLS_CC);
                if(!ls_ins) {
                if(!kiss_class_exists(ls TSRMLS_CC)) {
                    ls_file_len = spprintf(&ls_file, 0, "%s%s%s", ls_dir, ls, status->ext_proc);
                    MAKE_STD_ZVAL(ls_file2);
                    ZVAL_STRINGL(ls_file2, ls_file, ls_file_len, 0);
                    flag = kiss_eval(KISS_REQUIRE_ONCE, ls_file2, NULL TSRMLS_CC);
                    zval_ptr_dtor(&ls_file2);
                    if(!flag) {
                        zend_throw_exception_ex(NULL, KISS_E_CLSFILE TSRMLS_CC, "找不到类<b>%s</b>的定义文件!", ls);
                        efree(ls_key);
                        efree(ls);
                        if(ls_dir_abs) efree(ls_dir_abs);
                        return 0;
                    }
                }
                ls_ins = kiss_create_object(ls TSRMLS_CC);


                if(!ls_ins || !IS_ZEND_STD_OBJECT(*ls_ins)
                #ifndef PHP_WIN32
                    || !instanceof_function(Z_OBJCE_P(ls_ins), KISS_G(listener_ce) TSRMLS_CC)
                #endif
                ) {
                    zend_throw_exception_ex(NULL, KISS_E_INSTANCE TSRMLS_CC, "未能正确创建类%s的实例!", ls);

                    efree(ls_key);
                    efree(ls);
                    if(ls_ins) {
                     // zval_ptr_dtor(&ls_ins);

                     zval_ptr_dtor(&lss);
                 }

                    return 0;

                }
             kiss_set_cache_obj(ls, ls_ins TSRMLS_CC);
                }

                MAKE_STD_ZVAL(disp_func);
                ZVAL_STRING(disp_func, func_name, 1);
                MAKE_STD_ZVAL(ret);
                if(FAILURE==kiss_call_user_function
                    (NULL, &ls_ins, disp_func, ret, 0, NULL TSRMLS_CC)) {
                    zend_throw_exception_ex(NULL, KISS_E_CALLMTD TSRMLS_CC, "调用方法%s::%s()失败!", ls, func_name);
                    exe_flag = 0; // 避免重复调用释放内存的代码

                }
                kiss_set_ls_called(ls, type TSRMLS_CC);
                zval_ptr_dtor(&disp_func);
                zval_ptr_dtor(&ret);
                // zval_ptr_dtor(&ls_ins);

     }
        }
        if(lss) zval_ptr_dtor(&lss);
        // efree(ls_dir);

    }
    efree(ls_key);
    if(ls_dir_abs) efree(ls_dir_abs);
    return exe_flag;
}

/** 根据传入的类型,获得当前action的监听器。 */
static zval * kiss_get_listeners(ulong type TSRMLS_DC) {
    zval * ls, * ret, ** value;
    kiss_request * req;

    ls = KISS_LS_PRE_DISPATCH==type ?
        KISS_G(ls_pre_disp) : KISS_G(ls_post_disp);
    if(!ls) return NULL;
    req = KISS_G(request);
    if(zend_hash_find(Z_ARRVAL_P(ls), req->module,
        strlen(req->module)+1, (void**)&value)==FAILURE) {
        return NULL;
    }
    ls = *value;
    if(zend_hash_find(Z_ARRVAL_P(ls), req->controller,
        strlen(req->controller)+1, (void**)&value)==FAILURE) {
        return NULL;
    }
    ls = *value;
    MAKE_STD_ZVAL(ret);
    array_init(ret);
    if(zend_hash_find(Z_ARRVAL_P(ls), "", 1, (void**)&value)==SUCCESS) {
        php_array_merge(Z_ARRVAL_P(ret), Z_ARRVAL_PP(value), 0 TSRMLS_CC);
    }
    if(zend_hash_find(Z_ARRVAL_P(ls), req->action,
        strlen(req->action)+1, (void**)&value)==SUCCESS) {
        php_array_merge(Z_ARRVAL_P(ret), Z_ARRVAL_PP(value), 0 TSRMLS_CC);
    }
    return ret;
}

#endif // PHP_KISS_INNER_C