PHPAPI char *php_str_to_str_ex(char *haystack, int length, char *needle, int needle_len, char *str, int str_len, int *_new_length, int case_sensitivity, int replace_limit, int *replace_count) { char *new_str; int real_replace_count; if (needle_len < length) { char *end, *haystack_dup = NULL, *needle_dup = NULL; char *e, *s, *p, *r; if (needle_len == str_len) { new_str = estrndup(haystack, length); *_new_length = length; if (case_sensitivity) { end = new_str + length; for (p = new_str; (r = php_memnstr(p, needle, needle_len, end) && replace_limit > real_replace_count); p = r + needle_len) { memcpy(r, str, str_len); if (replace_count) { (*replace_count)++; } real_replace_count++; } } else { haystack_dup = estrndup(haystack, length); needle_dup = estrndup(needle, needle_len); php_strtolower(haystack_dup, length); php_strtolower(needle_dup, needle_len); end = haystack_dup + length; for (p = haystack_dup; (r = php_memnstr(p, needle_dup, needle_len, end) && replace_limit > real_replace_count); p = r + needle_len) { memcpy(new_str + (r - haystack_dup), str, str_len); if (replace_count) { (*replace_count)++; } real_replace_count++; } efree(haystack_dup); efree(needle_dup); } return new_str; } else { if (!case_sensitivity) { haystack_dup = estrndup(haystack, length); needle_dup = estrndup(needle, needle_len); php_strtolower(haystack_dup, length); php_strtolower(needle_dup, needle_len); } if (str_len < needle_len) { new_str = emalloc(length + 1); } else { int count = 0; char *o, *n, *endp; if (case_sensitivity) { o = haystack; n = needle; } else { o = haystack_dup; n = needle_dup; } endp = o + length; while ((o = php_memnstr(o, n, needle_len, endp))) { o += needle_len; count++; } if (count == 0) { /* Needle doesn't occur, shortcircuit the actual replacement. */ if (haystack_dup) { efree(haystack_dup); } if (needle_dup) { efree(needle_dup); } new_str = estrndup(haystack, length); if (_new_length) { *_new_length = length; } return new_str; } else { new_str = safe_emalloc(count, str_len - needle_len, length + 1); } } e = s = new_str; if (case_sensitivity) { end = haystack + length; for (p = haystack; (r = php_memnstr(p, needle, needle_len, end) && replace_limit > real_replace_count); p = r + needle_len) { memcpy(e, p, r - p); e += r - p; memcpy(e, str, str_len); e += str_len; if (replace_count) { (*replace_count)++; } real_replace_count++; } if (p < end) { memcpy(e, p, end - p); e += end - p; } } else { end = haystack_dup + length; for (p = haystack_dup; (r = php_memnstr(p, needle_dup, needle_len, end) && replace_limit > real_replace_count); p = r + needle_len) { memcpy(e, haystack + (p - haystack_dup), r - p); e += r - p; memcpy(e, str, str_len); e += str_len; if (replace_count) { (*replace_count)++; } real_replace_count++; } if (p < end) { memcpy(e, haystack + (p - haystack_dup), end - p); e += end - p; } } if (haystack_dup) { efree(haystack_dup); } if (needle_dup) { efree(needle_dup); } *e = '\0'; *_new_length = e - s; new_str = erealloc(new_str, *_new_length + 1); return new_str; } } else if (needle_len > length) { nothing_todo: *_new_length = length; new_str = estrndup(haystack, length); return new_str; } else { if (case_sensitivity ? strncmp(haystack, needle, length) : strncasecmp(haystack, needle, length)) { goto nothing_todo; } else { *_new_length = str_len; new_str = estrndup(str, str_len); if (replace_count) { (*replace_count)++; } return new_str; } } } /* }}} */ /* {{{ php_str_to_str */ PHPAPI char *php_str_to_str(char *haystack, int length, char *needle, int needle_len, char *str, int str_len, int *_new_length) { return php_str_to_str_ex(haystack, length, needle, needle_len, str, str_len, _new_length, 1, NULL); } /* }}} */ /* {{{ php_str_replace_in_subject */ static void php_str_replace_in_subject(zval *search, zval *replace, zval **subject, zval *result, int case_sensitivity, int replace_limit, int *replace_count) { zval **search_entry, **replace_entry = NULL, temp_result; char *replace_value = NULL; int replace_len = 0; /* Make sure we're dealing with strings. */ convert_to_string_ex(subject); Z_TYPE_P(result) = IS_STRING; if (Z_STRLEN_PP(subject) == 0) { ZVAL_STRINGL(result, "", 0, 1); return; } /* If search is an array */ if (Z_TYPE_P(search) == IS_ARRAY) { /* Duplicate subject string for repeated replacement */ *result = **subject; zval_copy_ctor(result); INIT_PZVAL(result); zend_hash_internal_pointer_reset(Z_ARRVAL_P(search)); if (Z_TYPE_P(replace) == IS_ARRAY) { zend_hash_internal_pointer_reset(Z_ARRVAL_P(replace)); } else { /* Set replacement value to the passed one */ replace_value = Z_STRVAL_P(replace); replace_len = Z_STRLEN_P(replace); } /* For each entry in the search array, get the entry */ while (zend_hash_get_current_data(Z_ARRVAL_P(search), (void **) &search_entry) == SUCCESS) { /* Make sure we're dealing with strings. */ SEPARATE_ZVAL(search_entry); convert_to_string(*search_entry); if (Z_STRLEN_PP(search_entry) == 0) { zend_hash_move_forward(Z_ARRVAL_P(search)); if (Z_TYPE_P(replace) == IS_ARRAY) { zend_hash_move_forward(Z_ARRVAL_P(replace)); } continue; } /* If replace is an array. */ if (Z_TYPE_P(replace) == IS_ARRAY) { /* Get current entry */ if (zend_hash_get_current_data(Z_ARRVAL_P(replace), (void **)&replace_entry) == SUCCESS) { /* Make sure we're dealing with strings. */ convert_to_string_ex(replace_entry); /* Set replacement value to the one we got from array */ replace_value = Z_STRVAL_PP(replace_entry); replace_len = Z_STRLEN_PP(replace_entry); zend_hash_move_forward(Z_ARRVAL_P(replace)); } else { /* We've run out of replacement strings, so use an empty one. */ replace_value = ""; replace_len = 0; } } if (Z_STRLEN_PP(search_entry) == 1) { php_char_to_str_ex(Z_STRVAL_P(result), Z_STRLEN_P(result), Z_STRVAL_PP(search_entry)[0], replace_value, replace_len, &temp_result, case_sensitivity, replace_limit, replace_count); } else if (Z_STRLEN_PP(search_entry) > 1) { Z_STRVAL(temp_result) = php_str_to_str_ex(Z_STRVAL_P(result), Z_STRLEN_P(result), Z_STRVAL_PP(search_entry), Z_STRLEN_PP(search_entry), replace_value, replace_len, &Z_STRLEN(temp_result), case_sensitivity, replace_count); } efree(Z_STRVAL_P(result)); Z_STRVAL_P(result) = Z_STRVAL(temp_result); Z_STRLEN_P(result) = Z_STRLEN(temp_result); if (Z_STRLEN_P(result) == 0) { return; } zend_hash_move_forward(Z_ARRVAL_P(search)); } } else { if (Z_STRLEN_P(search) == 1) { php_char_to_str_ex(Z_STRVAL_PP(subject), Z_STRLEN_PP(subject), Z_STRVAL_P(search)[0], Z_STRVAL_P(replace), Z_STRLEN_P(replace), result, case_sensitivity, replace_limit, replace_count); } else if (Z_STRLEN_P(search) > 1) { Z_STRVAL_P(result) = php_str_to_str_ex(Z_STRVAL_PP(subject), Z_STRLEN_PP(subject), Z_STRVAL_P(search), Z_STRLEN_P(search), Z_STRVAL_P(replace), Z_STRLEN_P(replace), &Z_STRLEN_P(result), case_sensitivity, replace_limit, replace_count); } else { *result = **subject; zval_copy_ctor(result); INIT_PZVAL(result); } } } /* }}} */ /* {{{ php_str_replace_common */ static void php_str_replace_common(INTERNAL_FUNCTION_PARAMETERS, int case_sensitivity) { zval **subject, **search, **replace, **subject_entry, **replace_limit, **zcount; zval *result; char *string_key; uint string_key_len; ulong num_key; int count = 0; int argc = ZEND_NUM_ARGS(); convert_to_long_ex(replace_limit); if (argc < 3 || argc > 5 || zend_get_parameters_ex(argc, &search, &replace, &subject, &replace_limit, &zcount) == FAILURE) { WRONG_PARAM_COUNT; } SEPARATE_ZVAL(search); SEPARATE_ZVAL(replace); SEPARATE_ZVAL(subject); /* Make sure we're dealing with strings and do the replacement. */ if (Z_TYPE_PP(search) != IS_ARRAY) { convert_to_string_ex(search); convert_to_string_ex(replace); } else if (Z_TYPE_PP(replace) != IS_ARRAY) { convert_to_string_ex(replace); } /* if subject is an array */ if (Z_TYPE_PP(subject) == IS_ARRAY) { array_init(return_value); zend_hash_internal_pointer_reset(Z_ARRVAL_PP(subject)); /* For each subject entry, convert it to string, then perform replacement and add the result to the return_value array. */ while (zend_hash_get_current_data(Z_ARRVAL_PP(subject), (void **)&subject_entry) == SUCCESS) { if (Z_TYPE_PP(subject_entry) != IS_ARRAY && Z_TYPE_PP(subject_entry) != IS_OBJECT) { MAKE_STD_ZVAL(result); SEPARATE_ZVAL(subject_entry); php_str_replace_in_subject(*search, *replace, subject_entry, result, case_sensitivity, (argc > 3) ? replace_limit : NULL, (argc > 4) ? &count : NULL); } else { ALLOC_ZVAL(result); ZVAL_ADDREF(*subject_entry); COPY_PZVAL_TO_ZVAL(*result, *subject_entry); } /* Add to return array */ switch (zend_hash_get_current_key_ex(Z_ARRVAL_PP(subject), &string_key, &string_key_len, &num_key, 0, NULL)) { case HASH_KEY_IS_STRING: add_assoc_zval_ex(return_value, string_key, string_key_len, result); break; case HASH_KEY_IS_LONG: add_index_zval(return_value, num_key, result); break; } zend_hash_move_forward(Z_ARRVAL_PP(subject)); } } else { /* if subject is not an array */ php_str_replace_in_subject(*search, *replace, subject, return_value, case_sensitivity, (argc > 3) ? replace_limit : NULL, (argc > 4) ? &count : NULL); } if (argc > 3) { zval_dtor(*zcount); ZVAL_LONG(*zcount, count); } } /* }}} */ /* {{{ proto mixed str_replace(mixed search, mixed replace, mixed subject [, int &replace_count]) Replaces all occurrences of search in haystack with replace */ PHP_FUNCTION(str_replace) { php_str_replace_common(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); }