Example #1
0
static zend_string *browscap_intern_str_ci(
		browscap_parser_ctx *ctx, zend_string *str, zend_bool persistent) {
	zend_string *lcname;
	zend_string *interned;
	ALLOCA_FLAG(use_heap);

	ZSTR_ALLOCA_ALLOC(lcname, ZSTR_LEN(str), use_heap);
	zend_str_tolower_copy(ZSTR_VAL(lcname), ZSTR_VAL(str), ZSTR_LEN(str));
	interned = zend_hash_find_ptr(&ctx->str_interned, lcname);

	if (interned) {
		zend_string_addref(interned);
	} else {
		interned = zend_string_dup(lcname, persistent);
		zend_hash_add_new_ptr(&ctx->str_interned, interned, interned);
	}

	ZSTR_ALLOCA_FREE(lcname, use_heap);
	return interned;
}
Example #2
0
ZEND_API zval *zend_get_constant_str(const char *name, size_t name_len)
{
	zend_constant *c;
	ALLOCA_FLAG(use_heap)

	if ((c = zend_hash_str_find_ptr(EG(zend_constants), name, name_len)) == NULL) {
		char *lcname = do_alloca(name_len + 1, use_heap);
		zend_str_tolower_copy(lcname, name, name_len);
		if ((c = zend_hash_str_find_ptr(EG(zend_constants), lcname, name_len)) != NULL) {
			if (c->flags & CONST_CS) {
				c = NULL;
			}
		} else {
			c = zend_get_special_constant(name, name_len);
		}
		free_alloca(lcname, use_heap);
	}

	return c ? &c->value : NULL;
}
Example #3
0
File: php_spl.c Project: 3F/php-src
static zend_class_entry * spl_find_ce_by_name(zend_string *name, zend_bool autoload)
{
	zend_class_entry *ce;

	if (!autoload) {
		zend_string *lc_name = zend_string_alloc(name->len, 0);
		zend_str_tolower_copy(lc_name->val, name->val, name->len);

		ce = zend_hash_find_ptr(EG(class_table), lc_name);
		zend_string_free(lc_name);
	} else {
 		ce = zend_lookup_class(name);
 	}
 	if (ce == NULL) {
		php_error_docref(NULL, E_WARNING, "Class %s does not exist%s", name->val, autoload ? " and could not be loaded" : "");
		return NULL;
	}

	return ce;
}
Example #4
0
static inline zend_constant *zend_get_constant_str_impl(const char *name, size_t name_len)
{
	zend_constant *c;
	ALLOCA_FLAG(use_heap)

	if ((c = zend_hash_str_find_ptr(EG(zend_constants), name, name_len)) == NULL) {
		char *lcname = do_alloca(name_len + 1, use_heap);
		zend_str_tolower_copy(lcname, name, name_len);
		if ((c = zend_hash_str_find_ptr(EG(zend_constants), lcname, name_len)) != NULL) {
			if (ZEND_CONSTANT_FLAGS(c) & CONST_CS) {
				c = NULL;
			}
		} else {
			c = zend_get_special_constant(name, name_len);
		}
		free_alloca(lcname, use_heap);
	}

	return c;
}
Example #5
0
ZEND_API zval *zend_get_constant(zend_string *name)
{
	zend_constant *c;
	ALLOCA_FLAG(use_heap)

	if ((c = zend_hash_find_ptr(EG(zend_constants), name)) == NULL) {
		char *lcname = do_alloca(ZSTR_LEN(name) + 1, use_heap);
		zend_str_tolower_copy(lcname, ZSTR_VAL(name), ZSTR_LEN(name));
		if ((c = zend_hash_str_find_ptr(EG(zend_constants), lcname, ZSTR_LEN(name))) != NULL) {
			if (c->flags & CONST_CS) {
				c = NULL;
			}
		} else {
			c = zend_get_special_constant(ZSTR_VAL(name), ZSTR_LEN(name));
		}
		free_alloca(lcname, use_heap);
	}

	return c ? &c->value : NULL;
}
Example #6
0
/* {{{ pthreads_get_method will attempt to apply pthreads specific modifiers */
zend_function * pthreads_get_method(PTHREADS_GET_METHOD_PASSTHRU_D) {
	zend_class_entry *scope;
	zend_function *call;
	zend_function *callable;
	char *lcname;
	int access = 0;
	PTHREAD thread = PTHREADS_FETCH_FROM(*pobject);
	
	if (thread) {
		switch((access=pthreads_modifiers_get(thread->modifiers, method TSRMLS_CC))){
			case ZEND_ACC_PRIVATE:
			case ZEND_ACC_PROTECTED:
				scope = Z_OBJCE_PP(pobject);
				lcname =  (char*) calloc(1, methodl+1);
				zend_str_tolower_copy(lcname, method, methodl);
				if (zend_hash_find(&scope->function_table, lcname, methodl+1, (void**)&call)==SUCCESS) {
					callable = (zend_function*) emalloc(sizeof(zend_function));
					callable->type = ZEND_OVERLOADED_FUNCTION;
					callable->common.function_name = call->common.function_name;
					callable->common.fn_flags = ZEND_ACC_PUBLIC;
					callable->common.scope = scope;
					callable->common.arg_info = call->common.arg_info;
					callable->common.num_args = call->common.num_args;
					callable->common.required_num_args = call->common.required_num_args;
#if PHP_VERSION_ID < 50400
					callable->common.pass_rest_by_reference = call->common.pass_rest_by_reference;
					callable->common.return_reference = call->common.return_reference;
#endif
					free(lcname);
					return callable;
				}
				free(lcname);
				/* TODO : if not found ? switch to default ? or return some error ? */

			default: call = zend_handlers->get_method(PTHREADS_GET_METHOD_PASSTHRU_C);
		}
		
	} else call = zend_handlers->get_method(PTHREADS_GET_METHOD_PASSTHRU_C);
	
	return call;
} /* }}} */
Example #7
0
static inline int unserialize_allowed_class(
		zend_string *class_name, php_unserialize_data_t *var_hashx)
{
	HashTable *classes = (*var_hashx)->allowed_classes;
	zend_string *lcname;
	int res;
	ALLOCA_FLAG(use_heap)

	if(classes == NULL) {
		return 1;
	}
	if(!zend_hash_num_elements(classes)) {
		return 0;
	}

	ZSTR_ALLOCA_ALLOC(lcname, ZSTR_LEN(class_name), use_heap);
	zend_str_tolower_copy(ZSTR_VAL(lcname), ZSTR_VAL(class_name), ZSTR_LEN(class_name));
	res = zend_hash_exists(classes, lcname);
	ZSTR_ALLOCA_FREE(lcname, use_heap);
	return res;
}
Example #8
0
static zend_class_entry * spl_find_ce_by_name(char *name, int len, zend_bool autoload TSRMLS_DC)
{
	zend_class_entry **ce;
	int found;

	if (!autoload) {
		char *lc_name;

		lc_name = do_alloca(len + 1);
		zend_str_tolower_copy(lc_name, name, len);

		found = zend_hash_find(EG(class_table), lc_name, len +1, (void **) &ce);
		free_alloca(lc_name);
	} else {
 		found = zend_lookup_class(name, len, &ce TSRMLS_CC);
 	}
 	if (found != SUCCESS) {
		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Class %s does not exist%s", name, autoload ? " and could not be loaded" : "");
		return NULL;
	}
	
	return *ce;
}
Example #9
0
/**
 *  Check whether a class with a certain name exists
 *  @param  classname
 *  @param  len
 *  @param  autoload
 *  @return bool
 */
bool class_exists(const char *classname, size_t len, bool autoload) 
{
    // we need the tsrm_ls variable
    TSRMLS_FETCH();

    // we're going to load a class-entry
    zend_class_entry **ce;

    // should we autoload the class?
    if (autoload) 
    {
        // no auto-load
        if (SUCCESS != zend_lookup_class(classname, len, &ce TSRMLS_CC)) return false;

        // the found "class" could also be an interface or trait, which we do no want
        return ((*ce)->ce_flags & (ZEND_ACC_INTERFACE | (ZEND_ACC_TRAIT - ZEND_ACC_EXPLICIT_ABSTRACT_CLASS))) == 0;
    }
    else
    {
        // starting slashes can be ignored
        if (len > 0 && classname[0] == '\\') { classname++; len--; }
        
        // all classes are in lowercase in the hash, so we make 
        // a temporary buffer for storing the lowercase class name
        // (is this smart? memory allocation is expensive!)
        std::unique_ptr<char[]> lc_name(new char[len + 1]);
        
        // copy the name to lowercase, but ignore the starting slash (if there is one)
        zend_str_tolower_copy(lc_name.get(), classname, len);

        // see if there is a class with this name
        if (SUCCESS != zend_hash_find(EG(class_table), lc_name.get(), len + 1, (void **) &ce)) return false;
        
        // the found "class" could also be an interface or trait, which we do no want
        return !(((*ce)->ce_flags & (ZEND_ACC_INTERFACE | ZEND_ACC_TRAIT)) > ZEND_ACC_EXPLICIT_ABSTRACT_CLASS);
    }
}
Example #10
0
File: pdo.c Project: 0x1111/php-src
PDO_API char *php_pdo_str_tolower_dup(const char *src, int len) /* {{{ */
{
	char *dest = emalloc(len + 1);
	zend_str_tolower_copy(dest, src, len);
	return dest;
}
Example #11
0
ZEND_API zval *zend_get_constant_ex(zend_string *cname, zend_class_entry *scope, zend_ulong flags)
{
	zend_constant *c;
	const char *colon;
	zend_class_entry *ce = NULL;
	zend_string *class_name;
	const char *name = cname->val;
	size_t name_len = cname->len;

	/* Skip leading \\ */
	if (name[0] == '\\') {
		name += 1;
		name_len -= 1;
		cname = NULL;
	}

	if ((colon = zend_memrchr(name, ':', name_len)) &&
	    colon > name && (*(colon - 1) == ':')) {
		int class_name_len = colon - name - 1;
		size_t const_name_len = name_len - class_name_len - 2;
		zend_string *constant_name = zend_string_init(colon + 1, const_name_len, 0);
		char *lcname;
		zval *ret_constant = NULL;
		ALLOCA_FLAG(use_heap)

		class_name = zend_string_init(name, class_name_len, 0);
		lcname = do_alloca(class_name_len + 1, use_heap);
		zend_str_tolower_copy(lcname, name, class_name_len);
		if (!scope) {
			if (EG(current_execute_data)) {
				scope = EG(scope);
			} else {
				scope = CG(active_class_entry);
			}
		}

		if (class_name_len == sizeof("self")-1 &&
		    !memcmp(lcname, "self", sizeof("self")-1)) {
			if (UNEXPECTED(!scope)) {
				zend_error(E_EXCEPTION | E_ERROR, "Cannot access self:: when no class scope is active");
				return NULL;
			}
			ce = scope;
		} else if (class_name_len == sizeof("parent")-1 &&
		           !memcmp(lcname, "parent", sizeof("parent")-1)) {
			if (UNEXPECTED(!scope)) {
				zend_error(E_EXCEPTION | E_ERROR, "Cannot access parent:: when no class scope is active");
				return NULL;
			} else if (UNEXPECTED(!scope->parent)) {
				zend_error(E_EXCEPTION | E_ERROR, "Cannot access parent:: when current class scope has no parent");
				return NULL;
			} else {
				ce = scope->parent;
			}
		} else if (class_name_len == sizeof("static")-1 &&
		           !memcmp(lcname, "static", sizeof("static")-1)) {
			ce = zend_get_called_scope(EG(current_execute_data));
			if (UNEXPECTED(!ce)) {
				zend_error(E_EXCEPTION | E_ERROR, "Cannot access static:: when no class scope is active");
				return NULL;
			}
		} else {
			ce = zend_fetch_class(class_name, flags);
		}
		free_alloca(lcname, use_heap);
		if (ce) {
			ret_constant = zend_hash_find(&ce->constants_table, constant_name);
			if (ret_constant == NULL) {
				if ((flags & ZEND_FETCH_CLASS_SILENT) == 0) {
					zend_error(E_EXCEPTION | E_ERROR, "Undefined class constant '%s::%s'", class_name->val, constant_name->val);
					zend_string_release(class_name);
					zend_string_free(constant_name);
					return NULL;
				}
			} else if (Z_ISREF_P(ret_constant)) {
				ret_constant = Z_REFVAL_P(ret_constant);
			}
		}
		zend_string_release(class_name);
		zend_string_free(constant_name);
		if (ret_constant && Z_CONSTANT_P(ret_constant)) {
			if (UNEXPECTED(zval_update_constant_ex(ret_constant, 1, ce) != SUCCESS)) {
				return NULL;
			}
		}
		return ret_constant;
	}

	/* non-class constant */
	if ((colon = zend_memrchr(name, '\\', name_len)) != NULL) {
		/* compound constant name */
		int prefix_len = colon - name;
		size_t const_name_len = name_len - prefix_len - 1;
		const char *constant_name = colon + 1;
		char *lcname;
		size_t lcname_len;
		ALLOCA_FLAG(use_heap)

		lcname_len = prefix_len + 1 + const_name_len;
		lcname = do_alloca(lcname_len + 1, use_heap);
		zend_str_tolower_copy(lcname, name, prefix_len);
		/* Check for namespace constant */

		lcname[prefix_len] = '\\';
		memcpy(lcname + prefix_len + 1, constant_name, const_name_len + 1);

		if ((c = zend_hash_str_find_ptr(EG(zend_constants), lcname, lcname_len)) == NULL) {
			/* try lowercase */
			zend_str_tolower(lcname + prefix_len + 1, const_name_len);
			if ((c = zend_hash_str_find_ptr(EG(zend_constants), lcname, lcname_len)) != NULL) {
				if ((c->flags & CONST_CS) != 0) {
					c = NULL;
				}
			}
		}
		free_alloca(lcname, use_heap);
		if (c) {
			return &c->value;
		}
		/* name requires runtime resolution, need to check non-namespaced name */
		if ((flags & IS_CONSTANT_UNQUALIFIED) != 0) {
			return zend_get_constant_str(constant_name, const_name_len);
		}
		return NULL;
	}

	if (cname) {
		return zend_get_constant(cname);
	} else {
		return zend_get_constant_str(name, name_len);
	}
}
Example #12
0
ZEND_API zval *zend_get_constant_ex(zend_string *cname, zend_class_entry *scope, uint32_t flags)
{
	zend_constant *c;
	const char *colon;
	zend_class_entry *ce = NULL;
	const char *name = ZSTR_VAL(cname);
	size_t name_len = ZSTR_LEN(cname);

	/* Skip leading \\ */
	if (name[0] == '\\') {
		name += 1;
		name_len -= 1;
		cname = NULL;
	}

	if ((colon = zend_memrchr(name, ':', name_len)) &&
	    colon > name && (*(colon - 1) == ':')) {
		int class_name_len = colon - name - 1;
		size_t const_name_len = name_len - class_name_len - 2;
		zend_string *constant_name = zend_string_init(colon + 1, const_name_len, 0);
		zend_string *class_name = zend_string_init(name, class_name_len, 0);
		zval *ret_constant = NULL;

		if (zend_string_equals_literal_ci(class_name, "self")) {
			if (UNEXPECTED(!scope)) {
				zend_throw_error(NULL, "Cannot access self:: when no class scope is active");
				goto failure;
			}
			ce = scope;
		} else if (zend_string_equals_literal_ci(class_name, "parent")) {
			if (UNEXPECTED(!scope)) {
				zend_throw_error(NULL, "Cannot access parent:: when no class scope is active");
				goto failure;
			} else if (UNEXPECTED(!scope->parent)) {
				zend_throw_error(NULL, "Cannot access parent:: when current class scope has no parent");
				goto failure;
			} else {
				ce = scope->parent;
			}
		} else if (zend_string_equals_literal_ci(class_name, "static")) {
			ce = zend_get_called_scope(EG(current_execute_data));
			if (UNEXPECTED(!ce)) {
				zend_throw_error(NULL, "Cannot access static:: when no class scope is active");
				goto failure;
			}
		} else {
			ce = zend_fetch_class(class_name, flags);
		}
		if (ce) {
			zend_class_constant *c = zend_hash_find_ptr(&ce->constants_table, constant_name);
			if (c == NULL) {
				if ((flags & ZEND_FETCH_CLASS_SILENT) == 0) {
					zend_throw_error(NULL, "Undefined class constant '%s::%s'", ZSTR_VAL(class_name), ZSTR_VAL(constant_name));
					goto failure;
				}
				ret_constant = NULL;
			} else {
				if (!zend_verify_const_access(c, scope)) {
					zend_throw_error(NULL, "Cannot access %s const %s::%s", zend_visibility_string(Z_ACCESS_FLAGS(c->value)), ZSTR_VAL(class_name), ZSTR_VAL(constant_name));
					goto failure;
				}
				ret_constant = &c->value;
			}
		}

		if (ret_constant && Z_CONSTANT_P(ret_constant)) {
			if (Z_TYPE_P(ret_constant) == IS_CONSTANT_AST) {
				if (IS_CONSTANT_VISITED(ret_constant)) {
					zend_throw_error(NULL, "Cannot declare self-referencing constant '%s::%s'", ZSTR_VAL(class_name), ZSTR_VAL(constant_name));
					ret_constant = NULL;
					goto failure;
				}
				MARK_CONSTANT_VISITED(ret_constant);
			}
			if (UNEXPECTED(zval_update_constant_ex(ret_constant, ce) != SUCCESS)) {
				RESET_CONSTANT_VISITED(ret_constant);
				ret_constant = NULL;
				goto failure;
			}
			RESET_CONSTANT_VISITED(ret_constant);
		}
failure:
		zend_string_release(class_name);
		zend_string_free(constant_name);
		return ret_constant;
	}

	/* non-class constant */
	if ((colon = zend_memrchr(name, '\\', name_len)) != NULL) {
		/* compound constant name */
		int prefix_len = colon - name;
		size_t const_name_len = name_len - prefix_len - 1;
		const char *constant_name = colon + 1;
		char *lcname;
		size_t lcname_len;
		ALLOCA_FLAG(use_heap)

		lcname_len = prefix_len + 1 + const_name_len;
		lcname = do_alloca(lcname_len + 1, use_heap);
		zend_str_tolower_copy(lcname, name, prefix_len);
		/* Check for namespace constant */

		lcname[prefix_len] = '\\';
		memcpy(lcname + prefix_len + 1, constant_name, const_name_len + 1);

		if ((c = zend_hash_str_find_ptr(EG(zend_constants), lcname, lcname_len)) == NULL) {
			/* try lowercase */
			zend_str_tolower(lcname + prefix_len + 1, const_name_len);
			if ((c = zend_hash_str_find_ptr(EG(zend_constants), lcname, lcname_len)) != NULL) {
				if ((c->flags & CONST_CS) != 0) {
					c = NULL;
				}
			}
		}
		free_alloca(lcname, use_heap);
		if (c) {
			return &c->value;
		}
		/* name requires runtime resolution, need to check non-namespaced name */
		if ((flags & IS_CONSTANT_UNQUALIFIED) != 0) {
			return zend_get_constant_str(constant_name, const_name_len);
		}
		return NULL;
	}

	if (cname) {
		return zend_get_constant(cname);
	} else {
		return zend_get_constant_str(name, name_len);
	}
}
Example #13
0
/* {{{ pthreads_call_method */
int pthreads_call_method(PTHREADS_CALL_METHOD_PASSTHRU_D) {
	zval 					***argv = NULL, zmethod, *zresult;
	zend_function 			*call = NULL;
	zend_fcall_info 		info;
	zend_fcall_info_cache	cache;
	zend_class_entry		*scope;
	int 					called = -1, argc = ZEND_NUM_ARGS(), access = ZEND_ACC_PUBLIC, mlength = 0;
	char					*lcname;
	zend_bool				unprotect;
	
	if (getThis()) {
		PTHREAD thread = PTHREADS_FETCH;
		if (thread) {
			switch((access=pthreads_modifiers_get(thread->modifiers, method TSRMLS_CC))){
				case ZEND_ACC_PRIVATE:
				case ZEND_ACC_PROTECTED: {
					scope = Z_OBJCE_P(getThis());
					
					/*
					* Stop invalid private method calls
					*/
					if (access == ZEND_ACC_PRIVATE && !PTHREADS_IN_THREAD(thread)) {
						zend_error_noreturn(
							E_ERROR, 
							"pthreads detected an attempt to call private method %s::%s from outside the threading context", 
							scope->name,
							method
						);
						return FAILURE;
					}
					
					/*
					* Get arguments from stack
					*/
					if (ZEND_NUM_ARGS()) 
					{
						argv = safe_emalloc(sizeof(zval **), argc, 0);
						if (argv) {
							zend_get_parameters_array_ex(argc, argv);
						}
					}
							
					mlength = strlen(method);
					lcname =  calloc(1, mlength+1);
					zend_str_tolower_copy(lcname, method, mlength);
					
					if (zend_hash_find(&scope->function_table, lcname, mlength+1, (void**)&call)==SUCCESS) {
						if (call) {
							/*
							* Make protected method call
							*/
							{
								if (access != ZEND_ACC_PROTECTED || pthreads_modifiers_protect(thread->modifiers, method, &unprotect TSRMLS_CC)) {
								
									ZVAL_STRINGL(&zmethod, method, strlen(method), 0);
									
									info.size = sizeof(info);
									info.object_ptr = getThis();
									info.function_name = &zmethod;
									info.retval_ptr_ptr = &zresult;
									info.no_separation = 1;
									info.symbol_table = NULL;
									info.param_count = argc;
									info.params = argv;
									
									cache.initialized = 1;
									cache.function_handler = call;
									cache.calling_scope = EG(called_scope);
									cache.called_scope = scope;
									cache.object_ptr = getThis();
									
									if ((called=zend_call_function(&info, &cache TSRMLS_CC))!=SUCCESS) {
										zend_error_noreturn(
											E_ERROR, 
											"pthreads has experienced an internal error while calling %s method %s::%s and cannot continue", 
											(access == ZEND_ACC_PROTECTED) ? "protected" : "private",
											scope->name,
											method
										);
									} else {
#if PHP_VERSION_ID > 50399
										{
											zend_op_array *ops = (zend_op_array*) call;
										
											if (ops) {
												if (ops->run_time_cache) {
													efree(ops->run_time_cache);
													ops->run_time_cache = NULL;
												}
											}
										}
#endif
										if (!return_value_used) {
											zval_ptr_dtor(&zresult);
										} else {
											ZVAL_ZVAL(return_value, zresult, 1, 1);
										}
									}
									
									if (access == ZEND_ACC_PROTECTED) {
										pthreads_modifiers_unprotect(thread->modifiers, method, unprotect TSRMLS_CC);
									}
								} else {
									zend_error_noreturn(
										E_ERROR, 
										"pthreads has experienced an internal error while calling %s method %s::%s and cannot continue", 
										(access == ZEND_ACC_PROTECTED) ? "protected" : "private",
										scope->name,
										method
									);
									called = FAILURE;
								}
							}
						} else {
							zend_error_noreturn(
								E_ERROR, 
								"pthreads has experienced an internal error while finding %s method %s::%s and cannot continue", 
								(access == ZEND_ACC_PROTECTED) ? "protected" : "private",
								scope->name,
								method
							);
							called = FAILURE;
						}
					}
					/*
					* Free unstacked arguments
					*/
					if (argc) {
						efree(argv);
					}
					free(lcname);
					return called;
				} break;
			}
		}
	}
	
	switch (called) {
		case -1: 
			return zend_handlers->call_method(PTHREADS_CALL_METHOD_PASSTHRU_C);
			
		default: return called;
	}
	
} /* }}} */
Example #14
0
static int browser_reg_compare(
		zval *entry_zv, int num_args, va_list args, zend_hash_key *key) /* {{{ */
{
	browscap_entry *entry = Z_PTR_P(entry_zv);
	zend_string *agent_name = va_arg(args, zend_string *);
	browscap_entry **found_entry_ptr = va_arg(args, browscap_entry **);
	browscap_entry *found_entry = *found_entry_ptr;
	ALLOCA_FLAG(use_heap);
	zend_string *pattern_lc, *regex;
	const char *cur;
	int i;

	pcre *re;
	int re_options;
	pcre_extra *re_extra;

	/* Agent name too short */
	if (ZSTR_LEN(agent_name) < browscap_get_minimum_length(entry)) {
		return 0;
	}

	/* Quickly discard patterns where the prefix doesn't match. */
	if (zend_binary_strcasecmp(
			ZSTR_VAL(agent_name), entry->prefix_len,
			ZSTR_VAL(entry->pattern), entry->prefix_len) != 0) {
		return 0;
	}

	/* Lowercase the pattern, the agent name is already lowercase */
	ZSTR_ALLOCA_ALLOC(pattern_lc, ZSTR_LEN(entry->pattern), use_heap);
	zend_str_tolower_copy(ZSTR_VAL(pattern_lc), ZSTR_VAL(entry->pattern), ZSTR_LEN(entry->pattern));

	/* Check if the agent contains the "contains" portions */
	cur = ZSTR_VAL(agent_name) + entry->prefix_len;
	for (i = 0; i < BROWSCAP_NUM_CONTAINS; i++) {
		if (entry->contains_len[i] != 0) {
			cur = zend_memnstr(cur,
				ZSTR_VAL(pattern_lc) + entry->contains_start[i],
				entry->contains_len[i],
				ZSTR_VAL(agent_name) + ZSTR_LEN(agent_name));
			if (!cur) {
				ZSTR_ALLOCA_FREE(pattern_lc, use_heap);
				return 0;
			}
			cur += entry->contains_len[i];
		}
	}

	/* See if we have an exact match, if so, we're done... */
	if (zend_string_equals(agent_name, pattern_lc)) {
		*found_entry_ptr = entry;
		ZSTR_ALLOCA_FREE(pattern_lc, use_heap);
		return ZEND_HASH_APPLY_STOP;
	}

	regex = browscap_convert_pattern(entry->pattern, 0);
	re = pcre_get_compiled_regex(regex, &re_extra, &re_options);
	if (re == NULL) {
		ZSTR_ALLOCA_FREE(pattern_lc, use_heap);
		zend_string_release(regex);
		return 0;
	}

	if (pcre_exec(re, re_extra, ZSTR_VAL(agent_name), ZSTR_LEN(agent_name), 0, re_options, NULL, 0) == 0) {
		/* If we've found a possible browser, we need to do a comparison of the
		   number of characters changed in the user agent being checked versus
		   the previous match found and the current match. */
		if (found_entry) {
			size_t i, prev_len = 0, curr_len = 0;
			zend_string *previous_match = found_entry->pattern;
			zend_string *current_match = entry->pattern;

			for (i = 0; i < ZSTR_LEN(previous_match); i++) {
				switch (ZSTR_VAL(previous_match)[i]) {
					case '?':
					case '*':
						/* do nothing, ignore these characters in the count */
					break;

					default:
						++prev_len;
				}
			}

			for (i = 0; i < ZSTR_LEN(current_match); i++) {
				switch (ZSTR_VAL(current_match)[i]) {
					case '?':
					case '*':
						/* do nothing, ignore these characters in the count */
					break;

					default:
						++curr_len;
				}
			}

			/* Pick which browser pattern replaces the least amount of
			   characters when compared to the original user agent string... */
			if (prev_len < curr_len) {
				*found_entry_ptr = entry;
			}
		} else {
			*found_entry_ptr = entry;
		}
	}

	ZSTR_ALLOCA_FREE(pattern_lc, use_heap);
	zend_string_release(regex);
	return 0;
}
Example #15
0
static zend_string *browscap_convert_pattern(zend_string *pattern, int persistent) /* {{{ */
{
	size_t i, j=0;
	char *t;
	zend_string *res;
	char *lc_pattern;
	ALLOCA_FLAG(use_heap);

	res = zend_string_alloc(browscap_compute_regex_len(pattern), persistent);
	t = ZSTR_VAL(res);

	lc_pattern = do_alloca(ZSTR_LEN(pattern) + 1, use_heap);
	zend_str_tolower_copy(lc_pattern, ZSTR_VAL(pattern), ZSTR_LEN(pattern));

	t[j++] = '~';
	t[j++] = '^';

	for (i = 0; i < ZSTR_LEN(pattern); i++, j++) {
		switch (lc_pattern[i]) {
			case '?':
				t[j] = '.';
				break;
			case '*':
				t[j++] = '.';
				t[j] = '*';
				break;
			case '.':
				t[j++] = '\\';
				t[j] = '.';
				break;
			case '\\':
				t[j++] = '\\';
				t[j] = '\\';
				break;
			case '(':
				t[j++] = '\\';
				t[j] = '(';
				break;
			case ')':
				t[j++] = '\\';
				t[j] = ')';
				break;
			case '~':
				t[j++] = '\\';
				t[j] = '~';
				break;
			case '+':
				t[j++] = '\\';
				t[j] = '+';
				break;
			default:
				t[j] = lc_pattern[i];
				break;
		}
	}

	t[j++] = '$';
	t[j++] = '~';
	t[j]=0;

	ZSTR_LEN(res) = j;
	free_alloca(lc_pattern, use_heap);
	return res;
}