1/* 2 +----------------------------------------------------------------------+ 3 | PHP Version 5 | 4 +----------------------------------------------------------------------+ 5 | Copyright (c) 1997-2013 The PHP Group | 6 +----------------------------------------------------------------------+ 7 | This source file is subject to version 3.01 of the PHP license, | 8 | that is bundled with this package in the file LICENSE, and is | 9 | available through the world-wide-web at the following url: | 10 | http://www.php.net/license/3_01.txt | 11 | If you did not receive a copy of the PHP license and are unable to | 12 | obtain it through the world-wide-web, please send a note to | 13 | license@php.net so we can mail you a copy immediately. | 14 +----------------------------------------------------------------------+ 15 | Authors: Rasmus Lerdorf <rasmus@php.net> | 16 | Stig S�ther Bakken <ssb@php.net> | 17 | Zeev Suraski <zeev@zend.com> | 18 +----------------------------------------------------------------------+ 19 */ 20 21/* $Id$ */ 22 23/* Synced with php 3.0 revision 1.193 1999-06-16 [ssb] */ 24 25#include <stdio.h> 26#include "php.h" 27#include "php_rand.h" 28#include "php_string.h" 29#include "php_variables.h" 30#ifdef HAVE_LOCALE_H 31# include <locale.h> 32#endif 33#ifdef HAVE_LANGINFO_H 34# include <langinfo.h> 35#endif 36#ifdef HAVE_MONETARY_H 37# include <monetary.h> 38#endif 39/* 40 * This define is here because some versions of libintl redefine setlocale 41 * to point to libintl_setlocale. That's a ridiculous thing to do as far 42 * as I am concerned, but with this define and the subsequent undef we 43 * limit the damage to just the actual setlocale() call in this file 44 * without turning zif_setlocale into zif_libintl_setlocale. -Rasmus 45 */ 46#define php_my_setlocale setlocale 47#ifdef HAVE_LIBINTL 48# include <libintl.h> /* For LC_MESSAGES */ 49 #ifdef setlocale 50 # undef setlocale 51 #endif 52#endif 53 54#include "scanf.h" 55#include "zend_API.h" 56#include "zend_execute.h" 57#include "php_globals.h" 58#include "basic_functions.h" 59#include "php_smart_str.h" 60#ifdef ZTS 61#include "TSRM.h" 62#endif 63 64/* For str_getcsv() support */ 65#include "ext/standard/file.h" 66 67#define STR_PAD_LEFT 0 68#define STR_PAD_RIGHT 1 69#define STR_PAD_BOTH 2 70#define PHP_PATHINFO_DIRNAME 1 71#define PHP_PATHINFO_BASENAME 2 72#define PHP_PATHINFO_EXTENSION 4 73#define PHP_PATHINFO_FILENAME 8 74#define PHP_PATHINFO_ALL (PHP_PATHINFO_DIRNAME | PHP_PATHINFO_BASENAME | PHP_PATHINFO_EXTENSION | PHP_PATHINFO_FILENAME) 75 76#define STR_STRSPN 0 77#define STR_STRCSPN 1 78 79/* {{{ register_string_constants 80 */ 81void register_string_constants(INIT_FUNC_ARGS) 82{ 83 REGISTER_LONG_CONSTANT("STR_PAD_LEFT", STR_PAD_LEFT, CONST_CS | CONST_PERSISTENT); 84 REGISTER_LONG_CONSTANT("STR_PAD_RIGHT", STR_PAD_RIGHT, CONST_CS | CONST_PERSISTENT); 85 REGISTER_LONG_CONSTANT("STR_PAD_BOTH", STR_PAD_BOTH, CONST_CS | CONST_PERSISTENT); 86 REGISTER_LONG_CONSTANT("PATHINFO_DIRNAME", PHP_PATHINFO_DIRNAME, CONST_CS | CONST_PERSISTENT); 87 REGISTER_LONG_CONSTANT("PATHINFO_BASENAME", PHP_PATHINFO_BASENAME, CONST_CS | CONST_PERSISTENT); 88 REGISTER_LONG_CONSTANT("PATHINFO_EXTENSION", PHP_PATHINFO_EXTENSION, CONST_CS | CONST_PERSISTENT); 89 REGISTER_LONG_CONSTANT("PATHINFO_FILENAME", PHP_PATHINFO_FILENAME, CONST_CS | CONST_PERSISTENT); 90 91#ifdef HAVE_LOCALECONV 92 /* If last members of struct lconv equal CHAR_MAX, no grouping is done */ 93 94/* This is bad, but since we are going to be hardcoding in the POSIX stuff anyway... */ 95# ifndef HAVE_LIMITS_H 96# define CHAR_MAX 127 97# endif 98 99 REGISTER_LONG_CONSTANT("CHAR_MAX", CHAR_MAX, CONST_CS | CONST_PERSISTENT); 100#endif 101 102#ifdef HAVE_LOCALE_H 103 REGISTER_LONG_CONSTANT("LC_CTYPE", LC_CTYPE, CONST_CS | CONST_PERSISTENT); 104 REGISTER_LONG_CONSTANT("LC_NUMERIC", LC_NUMERIC, CONST_CS | CONST_PERSISTENT); 105 REGISTER_LONG_CONSTANT("LC_TIME", LC_TIME, CONST_CS | CONST_PERSISTENT); 106 REGISTER_LONG_CONSTANT("LC_COLLATE", LC_COLLATE, CONST_CS | CONST_PERSISTENT); 107 REGISTER_LONG_CONSTANT("LC_MONETARY", LC_MONETARY, CONST_CS | CONST_PERSISTENT); 108 REGISTER_LONG_CONSTANT("LC_ALL", LC_ALL, CONST_CS | CONST_PERSISTENT); 109# ifdef LC_MESSAGES 110 REGISTER_LONG_CONSTANT("LC_MESSAGES", LC_MESSAGES, CONST_CS | CONST_PERSISTENT); 111# endif 112#endif 113 114} 115/* }}} */ 116 117int php_tag_find(char *tag, int len, char *set); 118 119/* this is read-only, so it's ok */ 120static char hexconvtab[] = "0123456789abcdef"; 121 122/* localeconv mutex */ 123#ifdef ZTS 124static MUTEX_T locale_mutex = NULL; 125#endif 126 127/* {{{ php_bin2hex 128 */ 129static char *php_bin2hex(const unsigned char *old, const size_t oldlen, size_t *newlen) 130{ 131 register unsigned char *result = NULL; 132 size_t i, j; 133 134 result = (unsigned char *) safe_emalloc(oldlen, 2 * sizeof(char), 1); 135 136 for (i = j = 0; i < oldlen; i++) { 137 result[j++] = hexconvtab[old[i] >> 4]; 138 result[j++] = hexconvtab[old[i] & 15]; 139 } 140 result[j] = '\0'; 141 142 if (newlen) 143 *newlen = oldlen * 2 * sizeof(char); 144 145 return (char *)result; 146} 147/* }}} */ 148 149#ifdef HAVE_LOCALECONV 150/* {{{ localeconv_r 151 * glibc's localeconv is not reentrant, so lets make it so ... sorta */ 152PHPAPI struct lconv *localeconv_r(struct lconv *out) 153{ 154 struct lconv *res; 155 156# ifdef ZTS 157 tsrm_mutex_lock( locale_mutex ); 158# endif 159 160 /* localeconv doesn't return an error condition */ 161 res = localeconv(); 162 163 *out = *res; 164 165# ifdef ZTS 166 tsrm_mutex_unlock( locale_mutex ); 167# endif 168 169 return out; 170} 171/* }}} */ 172 173# ifdef ZTS 174/* {{{ PHP_MINIT_FUNCTION 175 */ 176PHP_MINIT_FUNCTION(localeconv) 177{ 178 locale_mutex = tsrm_mutex_alloc(); 179 return SUCCESS; 180} 181/* }}} */ 182 183/* {{{ PHP_MSHUTDOWN_FUNCTION 184 */ 185PHP_MSHUTDOWN_FUNCTION(localeconv) 186{ 187 tsrm_mutex_free( locale_mutex ); 188 locale_mutex = NULL; 189 return SUCCESS; 190} 191/* }}} */ 192# endif 193#endif 194 195/* {{{ proto string bin2hex(string data) 196 Converts the binary representation of data to hex */ 197PHP_FUNCTION(bin2hex) 198{ 199 char *result, *data; 200 size_t newlen; 201 int datalen; 202 203 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data, &datalen) == FAILURE) { 204 return; 205 } 206 207 result = php_bin2hex((unsigned char *)data, datalen, &newlen); 208 209 if (!result) { 210 RETURN_FALSE; 211 } 212 213 RETURN_STRINGL(result, newlen, 0); 214} 215/* }}} */ 216 217static void php_spn_common_handler(INTERNAL_FUNCTION_PARAMETERS, int behavior) /* {{{ */ 218{ 219 char *s11, *s22; 220 int len1, len2; 221 long start = 0, len = 0; 222 223 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|ll", &s11, &len1, 224 &s22, &len2, &start, &len) == FAILURE) { 225 return; 226 } 227 228 if (ZEND_NUM_ARGS() < 4) { 229 len = len1; 230 } 231 232 /* look at substr() function for more information */ 233 234 if (start < 0) { 235 start += len1; 236 if (start < 0) { 237 start = 0; 238 } 239 } else if (start > len1) { 240 RETURN_FALSE; 241 } 242 243 if (len < 0) { 244 len += (len1 - start); 245 if (len < 0) { 246 len = 0; 247 } 248 } 249 250 if (len > len1 - start) { 251 len = len1 - start; 252 } 253 254 if(len == 0) { 255 RETURN_LONG(0); 256 } 257 258 if (behavior == STR_STRSPN) { 259 RETURN_LONG(php_strspn(s11 + start /*str1_start*/, 260 s22 /*str2_start*/, 261 s11 + start + len /*str1_end*/, 262 s22 + len2 /*str2_end*/)); 263 } else if (behavior == STR_STRCSPN) { 264 RETURN_LONG(php_strcspn(s11 + start /*str1_start*/, 265 s22 /*str2_start*/, 266 s11 + start + len /*str1_end*/, 267 s22 + len2 /*str2_end*/)); 268 } 269 270} 271/* }}} */ 272 273/* {{{ proto int strspn(string str, string mask [, start [, len]]) 274 Finds length of initial segment consisting entirely of characters found in mask. If start or/and length is provided works like strspn(substr($s,$start,$len),$good_chars) */ 275PHP_FUNCTION(strspn) 276{ 277 php_spn_common_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, STR_STRSPN); 278} 279/* }}} */ 280 281/* {{{ proto int strcspn(string str, string mask [, start [, len]]) 282 Finds length of initial segment consisting entirely of characters not found in mask. If start or/and length is provide works like strcspn(substr($s,$start,$len),$bad_chars) */ 283PHP_FUNCTION(strcspn) 284{ 285 php_spn_common_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, STR_STRCSPN); 286} 287/* }}} */ 288 289/* {{{ PHP_MINIT_FUNCTION(nl_langinfo) */ 290#if HAVE_NL_LANGINFO 291PHP_MINIT_FUNCTION(nl_langinfo) 292{ 293#define REGISTER_NL_LANGINFO_CONSTANT(x) REGISTER_LONG_CONSTANT(#x, x, CONST_CS | CONST_PERSISTENT) 294#ifdef ABDAY_1 295 REGISTER_NL_LANGINFO_CONSTANT(ABDAY_1); 296 REGISTER_NL_LANGINFO_CONSTANT(ABDAY_2); 297 REGISTER_NL_LANGINFO_CONSTANT(ABDAY_3); 298 REGISTER_NL_LANGINFO_CONSTANT(ABDAY_4); 299 REGISTER_NL_LANGINFO_CONSTANT(ABDAY_5); 300 REGISTER_NL_LANGINFO_CONSTANT(ABDAY_6); 301 REGISTER_NL_LANGINFO_CONSTANT(ABDAY_7); 302#endif 303#ifdef DAY_1 304 REGISTER_NL_LANGINFO_CONSTANT(DAY_1); 305 REGISTER_NL_LANGINFO_CONSTANT(DAY_2); 306 REGISTER_NL_LANGINFO_CONSTANT(DAY_3); 307 REGISTER_NL_LANGINFO_CONSTANT(DAY_4); 308 REGISTER_NL_LANGINFO_CONSTANT(DAY_5); 309 REGISTER_NL_LANGINFO_CONSTANT(DAY_6); 310 REGISTER_NL_LANGINFO_CONSTANT(DAY_7); 311#endif 312#ifdef ABMON_1 313 REGISTER_NL_LANGINFO_CONSTANT(ABMON_1); 314 REGISTER_NL_LANGINFO_CONSTANT(ABMON_2); 315 REGISTER_NL_LANGINFO_CONSTANT(ABMON_3); 316 REGISTER_NL_LANGINFO_CONSTANT(ABMON_4); 317 REGISTER_NL_LANGINFO_CONSTANT(ABMON_5); 318 REGISTER_NL_LANGINFO_CONSTANT(ABMON_6); 319 REGISTER_NL_LANGINFO_CONSTANT(ABMON_7); 320 REGISTER_NL_LANGINFO_CONSTANT(ABMON_8); 321 REGISTER_NL_LANGINFO_CONSTANT(ABMON_9); 322 REGISTER_NL_LANGINFO_CONSTANT(ABMON_10); 323 REGISTER_NL_LANGINFO_CONSTANT(ABMON_11); 324 REGISTER_NL_LANGINFO_CONSTANT(ABMON_12); 325#endif 326#ifdef MON_1 327 REGISTER_NL_LANGINFO_CONSTANT(MON_1); 328 REGISTER_NL_LANGINFO_CONSTANT(MON_2); 329 REGISTER_NL_LANGINFO_CONSTANT(MON_3); 330 REGISTER_NL_LANGINFO_CONSTANT(MON_4); 331 REGISTER_NL_LANGINFO_CONSTANT(MON_5); 332 REGISTER_NL_LANGINFO_CONSTANT(MON_6); 333 REGISTER_NL_LANGINFO_CONSTANT(MON_7); 334 REGISTER_NL_LANGINFO_CONSTANT(MON_8); 335 REGISTER_NL_LANGINFO_CONSTANT(MON_9); 336 REGISTER_NL_LANGINFO_CONSTANT(MON_10); 337 REGISTER_NL_LANGINFO_CONSTANT(MON_11); 338 REGISTER_NL_LANGINFO_CONSTANT(MON_12); 339#endif 340#ifdef AM_STR 341 REGISTER_NL_LANGINFO_CONSTANT(AM_STR); 342#endif 343#ifdef PM_STR 344 REGISTER_NL_LANGINFO_CONSTANT(PM_STR); 345#endif 346#ifdef D_T_FMT 347 REGISTER_NL_LANGINFO_CONSTANT(D_T_FMT); 348#endif 349#ifdef D_FMT 350 REGISTER_NL_LANGINFO_CONSTANT(D_FMT); 351#endif 352#ifdef T_FMT 353 REGISTER_NL_LANGINFO_CONSTANT(T_FMT); 354#endif 355#ifdef T_FMT_AMPM 356 REGISTER_NL_LANGINFO_CONSTANT(T_FMT_AMPM); 357#endif 358#ifdef ERA 359 REGISTER_NL_LANGINFO_CONSTANT(ERA); 360#endif 361#ifdef ERA_YEAR 362 REGISTER_NL_LANGINFO_CONSTANT(ERA_YEAR); 363#endif 364#ifdef ERA_D_T_FMT 365 REGISTER_NL_LANGINFO_CONSTANT(ERA_D_T_FMT); 366#endif 367#ifdef ERA_D_FMT 368 REGISTER_NL_LANGINFO_CONSTANT(ERA_D_FMT); 369#endif 370#ifdef ERA_T_FMT 371 REGISTER_NL_LANGINFO_CONSTANT(ERA_T_FMT); 372#endif 373#ifdef ALT_DIGITS 374 REGISTER_NL_LANGINFO_CONSTANT(ALT_DIGITS); 375#endif 376#ifdef INT_CURR_SYMBOL 377 REGISTER_NL_LANGINFO_CONSTANT(INT_CURR_SYMBOL); 378#endif 379#ifdef CURRENCY_SYMBOL 380 REGISTER_NL_LANGINFO_CONSTANT(CURRENCY_SYMBOL); 381#endif 382#ifdef CRNCYSTR 383 REGISTER_NL_LANGINFO_CONSTANT(CRNCYSTR); 384#endif 385#ifdef MON_DECIMAL_POINT 386 REGISTER_NL_LANGINFO_CONSTANT(MON_DECIMAL_POINT); 387#endif 388#ifdef MON_THOUSANDS_SEP 389 REGISTER_NL_LANGINFO_CONSTANT(MON_THOUSANDS_SEP); 390#endif 391#ifdef MON_GROUPING 392 REGISTER_NL_LANGINFO_CONSTANT(MON_GROUPING); 393#endif 394#ifdef POSITIVE_SIGN 395 REGISTER_NL_LANGINFO_CONSTANT(POSITIVE_SIGN); 396#endif 397#ifdef NEGATIVE_SIGN 398 REGISTER_NL_LANGINFO_CONSTANT(NEGATIVE_SIGN); 399#endif 400#ifdef INT_FRAC_DIGITS 401 REGISTER_NL_LANGINFO_CONSTANT(INT_FRAC_DIGITS); 402#endif 403#ifdef FRAC_DIGITS 404 REGISTER_NL_LANGINFO_CONSTANT(FRAC_DIGITS); 405#endif 406#ifdef P_CS_PRECEDES 407 REGISTER_NL_LANGINFO_CONSTANT(P_CS_PRECEDES); 408#endif 409#ifdef P_SEP_BY_SPACE 410 REGISTER_NL_LANGINFO_CONSTANT(P_SEP_BY_SPACE); 411#endif 412#ifdef N_CS_PRECEDES 413 REGISTER_NL_LANGINFO_CONSTANT(N_CS_PRECEDES); 414#endif 415#ifdef N_SEP_BY_SPACE 416 REGISTER_NL_LANGINFO_CONSTANT(N_SEP_BY_SPACE); 417#endif 418#ifdef P_SIGN_POSN 419 REGISTER_NL_LANGINFO_CONSTANT(P_SIGN_POSN); 420#endif 421#ifdef N_SIGN_POSN 422 REGISTER_NL_LANGINFO_CONSTANT(N_SIGN_POSN); 423#endif 424#ifdef DECIMAL_POINT 425 REGISTER_NL_LANGINFO_CONSTANT(DECIMAL_POINT); 426#endif 427#ifdef RADIXCHAR 428 REGISTER_NL_LANGINFO_CONSTANT(RADIXCHAR); 429#endif 430#ifdef THOUSANDS_SEP 431 REGISTER_NL_LANGINFO_CONSTANT(THOUSANDS_SEP); 432#endif 433#ifdef THOUSEP 434 REGISTER_NL_LANGINFO_CONSTANT(THOUSEP); 435#endif 436#ifdef GROUPING 437 REGISTER_NL_LANGINFO_CONSTANT(GROUPING); 438#endif 439#ifdef YESEXPR 440 REGISTER_NL_LANGINFO_CONSTANT(YESEXPR); 441#endif 442#ifdef NOEXPR 443 REGISTER_NL_LANGINFO_CONSTANT(NOEXPR); 444#endif 445#ifdef YESSTR 446 REGISTER_NL_LANGINFO_CONSTANT(YESSTR); 447#endif 448#ifdef NOSTR 449 REGISTER_NL_LANGINFO_CONSTANT(NOSTR); 450#endif 451#ifdef CODESET 452 REGISTER_NL_LANGINFO_CONSTANT(CODESET); 453#endif 454#undef REGISTER_NL_LANGINFO_CONSTANT 455 return SUCCESS; 456} 457/* }}} */ 458 459/* {{{ proto string nl_langinfo(int item) 460 Query language and locale information */ 461PHP_FUNCTION(nl_langinfo) 462{ 463 long item; 464 char *value; 465 466 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &item) == FAILURE) { 467 return; 468 } 469 470 switch(item) { /* {{{ */ 471#ifdef ABDAY_1 472 case ABDAY_1: 473 case ABDAY_2: 474 case ABDAY_3: 475 case ABDAY_4: 476 case ABDAY_5: 477 case ABDAY_6: 478 case ABDAY_7: 479#endif 480#ifdef DAY_1 481 case DAY_1: 482 case DAY_2: 483 case DAY_3: 484 case DAY_4: 485 case DAY_5: 486 case DAY_6: 487 case DAY_7: 488#endif 489#ifdef ABMON_1 490 case ABMON_1: 491 case ABMON_2: 492 case ABMON_3: 493 case ABMON_4: 494 case ABMON_5: 495 case ABMON_6: 496 case ABMON_7: 497 case ABMON_8: 498 case ABMON_9: 499 case ABMON_10: 500 case ABMON_11: 501 case ABMON_12: 502#endif 503#ifdef MON_1 504 case MON_1: 505 case MON_2: 506 case MON_3: 507 case MON_4: 508 case MON_5: 509 case MON_6: 510 case MON_7: 511 case MON_8: 512 case MON_9: 513 case MON_10: 514 case MON_11: 515 case MON_12: 516#endif 517#ifdef AM_STR 518 case AM_STR: 519#endif 520#ifdef PM_STR 521 case PM_STR: 522#endif 523#ifdef D_T_FMT 524 case D_T_FMT: 525#endif 526#ifdef D_FMT 527 case D_FMT: 528#endif 529#ifdef T_FMT 530 case T_FMT: 531#endif 532#ifdef T_FMT_AMPM 533 case T_FMT_AMPM: 534#endif 535#ifdef ERA 536 case ERA: 537#endif 538#ifdef ERA_YEAR 539 case ERA_YEAR: 540#endif 541#ifdef ERA_D_T_FMT 542 case ERA_D_T_FMT: 543#endif 544#ifdef ERA_D_FMT 545 case ERA_D_FMT: 546#endif 547#ifdef ERA_T_FMT 548 case ERA_T_FMT: 549#endif 550#ifdef ALT_DIGITS 551 case ALT_DIGITS: 552#endif 553#ifdef INT_CURR_SYMBOL 554 case INT_CURR_SYMBOL: 555#endif 556#ifdef CURRENCY_SYMBOL 557 case CURRENCY_SYMBOL: 558#endif 559#ifdef CRNCYSTR 560 case CRNCYSTR: 561#endif 562#ifdef MON_DECIMAL_POINT 563 case MON_DECIMAL_POINT: 564#endif 565#ifdef MON_THOUSANDS_SEP 566 case MON_THOUSANDS_SEP: 567#endif 568#ifdef MON_GROUPING 569 case MON_GROUPING: 570#endif 571#ifdef POSITIVE_SIGN 572 case POSITIVE_SIGN: 573#endif 574#ifdef NEGATIVE_SIGN 575 case NEGATIVE_SIGN: 576#endif 577#ifdef INT_FRAC_DIGITS 578 case INT_FRAC_DIGITS: 579#endif 580#ifdef FRAC_DIGITS 581 case FRAC_DIGITS: 582#endif 583#ifdef P_CS_PRECEDES 584 case P_CS_PRECEDES: 585#endif 586#ifdef P_SEP_BY_SPACE 587 case P_SEP_BY_SPACE: 588#endif 589#ifdef N_CS_PRECEDES 590 case N_CS_PRECEDES: 591#endif 592#ifdef N_SEP_BY_SPACE 593 case N_SEP_BY_SPACE: 594#endif 595#ifdef P_SIGN_POSN 596 case P_SIGN_POSN: 597#endif 598#ifdef N_SIGN_POSN 599 case N_SIGN_POSN: 600#endif 601#ifdef DECIMAL_POINT 602 case DECIMAL_POINT: 603#elif defined(RADIXCHAR) 604 case RADIXCHAR: 605#endif 606#ifdef THOUSANDS_SEP 607 case THOUSANDS_SEP: 608#elif defined(THOUSEP) 609 case THOUSEP: 610#endif 611#ifdef GROUPING 612 case GROUPING: 613#endif 614#ifdef YESEXPR 615 case YESEXPR: 616#endif 617#ifdef NOEXPR 618 case NOEXPR: 619#endif 620#ifdef YESSTR 621 case YESSTR: 622#endif 623#ifdef NOSTR 624 case NOSTR: 625#endif 626#ifdef CODESET 627 case CODESET: 628#endif 629 break; 630 default: 631 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Item '%ld' is not valid", item); 632 RETURN_FALSE; 633 } 634 /* }}} */ 635 636 value = nl_langinfo(item); 637 if (value == NULL) { 638 RETURN_FALSE; 639 } else { 640 RETURN_STRING(value, 1); 641 } 642} 643#endif 644/* }}} */ 645 646#ifdef HAVE_STRCOLL 647/* {{{ proto int strcoll(string str1, string str2) 648 Compares two strings using the current locale */ 649PHP_FUNCTION(strcoll) 650{ 651 char *s1, *s2; 652 int s1len, s2len; 653 654 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &s1, &s1len, &s2, &s2len) == FAILURE) { 655 return; 656 } 657 658 RETURN_LONG(strcoll((const char *) s1, 659 (const char *) s2)); 660} 661/* }}} */ 662#endif 663 664/* {{{ php_charmask 665 * Fills a 256-byte bytemask with input. You can specify a range like 'a..z', 666 * it needs to be incrementing. 667 * Returns: FAILURE/SUCCESS whether the input was correct (i.e. no range errors) 668 */ 669static inline int php_charmask(unsigned char *input, int len, char *mask TSRMLS_DC) 670{ 671 unsigned char *end; 672 unsigned char c; 673 int result = SUCCESS; 674 675 memset(mask, 0, 256); 676 for (end = input+len; input < end; input++) { 677 c=*input; 678 if ((input+3 < end) && input[1] == '.' && input[2] == '.' 679 && input[3] >= c) { 680 memset(mask+c, 1, input[3] - c + 1); 681 input+=3; 682 } else if ((input+1 < end) && input[0] == '.' && input[1] == '.') { 683 /* Error, try to be as helpful as possible: 684 (a range ending/starting with '.' won't be captured here) */ 685 if (end-len >= input) { /* there was no 'left' char */ 686 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid '..'-range, no character to the left of '..'"); 687 result = FAILURE; 688 continue; 689 } 690 if (input+2 >= end) { /* there is no 'right' char */ 691 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid '..'-range, no character to the right of '..'"); 692 result = FAILURE; 693 continue; 694 } 695 if (input[-1] > input[2]) { /* wrong order */ 696 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid '..'-range, '..'-range needs to be incrementing"); 697 result = FAILURE; 698 continue; 699 } 700 /* FIXME: better error (a..b..c is the only left possibility?) */ 701 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid '..'-range"); 702 result = FAILURE; 703 continue; 704 } else { 705 mask[c]=1; 706 } 707 } 708 return result; 709} 710/* }}} */ 711 712/* {{{ php_trim() 713 * mode 1 : trim left 714 * mode 2 : trim right 715 * mode 3 : trim left and right 716 * what indicates which chars are to be trimmed. NULL->default (' \t\n\r\v\0') 717 */ 718PHPAPI char *php_trim(char *c, int len, char *what, int what_len, zval *return_value, int mode TSRMLS_DC) 719{ 720 register int i; 721 int trimmed = 0; 722 char mask[256]; 723 724 if (what) { 725 php_charmask((unsigned char*)what, what_len, mask TSRMLS_CC); 726 } else { 727 php_charmask((unsigned char*)" \n\r\t\v\0", 6, mask TSRMLS_CC); 728 } 729 730 if (mode & 1) { 731 for (i = 0; i < len; i++) { 732 if (mask[(unsigned char)c[i]]) { 733 trimmed++; 734 } else { 735 break; 736 } 737 } 738 len -= trimmed; 739 c += trimmed; 740 } 741 if (mode & 2) { 742 for (i = len - 1; i >= 0; i--) { 743 if (mask[(unsigned char)c[i]]) { 744 len--; 745 } else { 746 break; 747 } 748 } 749 } 750 751 if (return_value) { 752 RETVAL_STRINGL(c, len, 1); 753 } else { 754 return estrndup(c, len); 755 } 756 return ""; 757} 758/* }}} */ 759 760/* {{{ php_do_trim 761 * Base for trim(), rtrim() and ltrim() functions. 762 */ 763static void php_do_trim(INTERNAL_FUNCTION_PARAMETERS, int mode) 764{ 765 char *str; 766 char *what = NULL; 767 int str_len, what_len = 0; 768 769 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &str, &str_len, &what, &what_len) == FAILURE) { 770 return; 771 } 772 773 php_trim(str, str_len, what, what_len, return_value, mode TSRMLS_CC); 774} 775/* }}} */ 776 777/* {{{ proto string trim(string str [, string character_mask]) 778 Strips whitespace from the beginning and end of a string */ 779PHP_FUNCTION(trim) 780{ 781 php_do_trim(INTERNAL_FUNCTION_PARAM_PASSTHRU, 3); 782} 783/* }}} */ 784 785/* {{{ proto string rtrim(string str [, string character_mask]) 786 Removes trailing whitespace */ 787PHP_FUNCTION(rtrim) 788{ 789 php_do_trim(INTERNAL_FUNCTION_PARAM_PASSTHRU, 2); 790} 791/* }}} */ 792 793/* {{{ proto string ltrim(string str [, string character_mask]) 794 Strips whitespace from the beginning of a string */ 795PHP_FUNCTION(ltrim) 796{ 797 php_do_trim(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); 798} 799/* }}} */ 800 801/* {{{ proto string wordwrap(string str [, int width [, string break [, boolean cut]]]) 802 Wraps buffer to selected number of characters using string break char */ 803PHP_FUNCTION(wordwrap) 804{ 805 const char *text, *breakchar = "\n"; 806 char *newtext; 807 int textlen, breakcharlen = 1, newtextlen, chk; 808 size_t alloced; 809 long current = 0, laststart = 0, lastspace = 0; 810 long linelength = 75; 811 zend_bool docut = 0; 812 813 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lsb", &text, &textlen, &linelength, &breakchar, &breakcharlen, &docut) == FAILURE) { 814 return; 815 } 816 817 if (textlen == 0) { 818 RETURN_EMPTY_STRING(); 819 } 820 821 if (breakcharlen == 0) { 822 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Break string cannot be empty"); 823 RETURN_FALSE; 824 } 825 826 if (linelength == 0 && docut) { 827 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can't force cut when width is zero"); 828 RETURN_FALSE; 829 } 830 831 /* Special case for a single-character break as it needs no 832 additional storage space */ 833 if (breakcharlen == 1 && !docut) { 834 newtext = estrndup(text, textlen); 835 836 laststart = lastspace = 0; 837 for (current = 0; current < textlen; current++) { 838 if (text[current] == breakchar[0]) { 839 laststart = lastspace = current + 1; 840 } else if (text[current] == ' ') { 841 if (current - laststart >= linelength) { 842 newtext[current] = breakchar[0]; 843 laststart = current + 1; 844 } 845 lastspace = current; 846 } else if (current - laststart >= linelength && laststart != lastspace) { 847 newtext[lastspace] = breakchar[0]; 848 laststart = lastspace + 1; 849 } 850 } 851 852 RETURN_STRINGL(newtext, textlen, 0); 853 } else { 854 /* Multiple character line break or forced cut */ 855 if (linelength > 0) { 856 chk = (int)(textlen/linelength + 1); 857 newtext = safe_emalloc(chk, breakcharlen, textlen + 1); 858 alloced = textlen + chk * breakcharlen + 1; 859 } else { 860 chk = textlen; 861 alloced = textlen * (breakcharlen + 1) + 1; 862 newtext = safe_emalloc(textlen, (breakcharlen + 1), 1); 863 } 864 865 /* now keep track of the actual new text length */ 866 newtextlen = 0; 867 868 laststart = lastspace = 0; 869 for (current = 0; current < textlen; current++) { 870 if (chk <= 0) { 871 alloced += (int) (((textlen - current + 1)/linelength + 1) * breakcharlen) + 1; 872 newtext = erealloc(newtext, alloced); 873 chk = (int) ((textlen - current)/linelength) + 1; 874 } 875 /* when we hit an existing break, copy to new buffer, and 876 * fix up laststart and lastspace */ 877 if (text[current] == breakchar[0] 878 && current + breakcharlen < textlen 879 && !strncmp(text+current, breakchar, breakcharlen)) { 880 memcpy(newtext+newtextlen, text+laststart, current-laststart+breakcharlen); 881 newtextlen += current-laststart+breakcharlen; 882 current += breakcharlen - 1; 883 laststart = lastspace = current + 1; 884 chk--; 885 } 886 /* if it is a space, check if it is at the line boundary, 887 * copy and insert a break, or just keep track of it */ 888 else if (text[current] == ' ') { 889 if (current - laststart >= linelength) { 890 memcpy(newtext+newtextlen, text+laststart, current-laststart); 891 newtextlen += current - laststart; 892 memcpy(newtext+newtextlen, breakchar, breakcharlen); 893 newtextlen += breakcharlen; 894 laststart = current + 1; 895 chk--; 896 } 897 lastspace = current; 898 } 899 /* if we are cutting, and we've accumulated enough 900 * characters, and we haven't see a space for this line, 901 * copy and insert a break. */ 902 else if (current - laststart >= linelength 903 && docut && laststart >= lastspace) { 904 memcpy(newtext+newtextlen, text+laststart, current-laststart); 905 newtextlen += current - laststart; 906 memcpy(newtext+newtextlen, breakchar, breakcharlen); 907 newtextlen += breakcharlen; 908 laststart = lastspace = current; 909 chk--; 910 } 911 /* if the current word puts us over the linelength, copy 912 * back up until the last space, insert a break, and move 913 * up the laststart */ 914 else if (current - laststart >= linelength 915 && laststart < lastspace) { 916 memcpy(newtext+newtextlen, text+laststart, lastspace-laststart); 917 newtextlen += lastspace - laststart; 918 memcpy(newtext+newtextlen, breakchar, breakcharlen); 919 newtextlen += breakcharlen; 920 laststart = lastspace = lastspace + 1; 921 chk--; 922 } 923 } 924 925 /* copy over any stragglers */ 926 if (laststart != current) { 927 memcpy(newtext+newtextlen, text+laststart, current-laststart); 928 newtextlen += current - laststart; 929 } 930 931 newtext[newtextlen] = '\0'; 932 /* free unused memory */ 933 newtext = erealloc(newtext, newtextlen+1); 934 935 RETURN_STRINGL(newtext, newtextlen, 0); 936 } 937} 938/* }}} */ 939 940/* {{{ php_explode 941 */ 942PHPAPI void php_explode(zval *delim, zval *str, zval *return_value, long limit) 943{ 944 char *p1, *p2, *endp; 945 946 endp = Z_STRVAL_P(str) + Z_STRLEN_P(str); 947 948 p1 = Z_STRVAL_P(str); 949 p2 = php_memnstr(Z_STRVAL_P(str), Z_STRVAL_P(delim), Z_STRLEN_P(delim), endp); 950 951 if (p2 == NULL) { 952 add_next_index_stringl(return_value, p1, Z_STRLEN_P(str), 1); 953 } else { 954 do { 955 add_next_index_stringl(return_value, p1, p2 - p1, 1); 956 p1 = p2 + Z_STRLEN_P(delim); 957 } while ((p2 = php_memnstr(p1, Z_STRVAL_P(delim), Z_STRLEN_P(delim), endp)) != NULL && 958 --limit > 1); 959 960 if (p1 <= endp) 961 add_next_index_stringl(return_value, p1, endp-p1, 1); 962 } 963} 964/* }}} */ 965 966/* {{{ php_explode_negative_limit 967 */ 968PHPAPI void php_explode_negative_limit(zval *delim, zval *str, zval *return_value, long limit) 969{ 970#define EXPLODE_ALLOC_STEP 64 971 char *p1, *p2, *endp; 972 973 endp = Z_STRVAL_P(str) + Z_STRLEN_P(str); 974 975 p1 = Z_STRVAL_P(str); 976 p2 = php_memnstr(Z_STRVAL_P(str), Z_STRVAL_P(delim), Z_STRLEN_P(delim), endp); 977 978 if (p2 == NULL) { 979 /* 980 do nothing since limit <= -1, thus if only one chunk - 1 + (limit) <= 0 981 by doing nothing we return empty array 982 */ 983 } else { 984 int allocated = EXPLODE_ALLOC_STEP, found = 0; 985 long i, to_return; 986 char **positions = emalloc(allocated * sizeof(char *)); 987 988 positions[found++] = p1; 989 do { 990 if (found >= allocated) { 991 allocated = found + EXPLODE_ALLOC_STEP;/* make sure we have enough memory */ 992 positions = erealloc(positions, allocated*sizeof(char *)); 993 } 994 positions[found++] = p1 = p2 + Z_STRLEN_P(delim); 995 } while ((p2 = php_memnstr(p1, Z_STRVAL_P(delim), Z_STRLEN_P(delim), endp)) != NULL); 996 997 to_return = limit + found; 998 /* limit is at least -1 therefore no need of bounds checking : i will be always less than found */ 999 for (i = 0;i < to_return;i++) { /* this checks also for to_return > 0 */ 1000 add_next_index_stringl(return_value, positions[i], 1001 (positions[i+1] - Z_STRLEN_P(delim)) - positions[i], 1002 1 1003 ); 1004 } 1005 efree(positions); 1006 } 1007#undef EXPLODE_ALLOC_STEP 1008} 1009/* }}} */ 1010 1011/* {{{ proto array explode(string separator, string str [, int limit]) 1012 Splits a string on string separator and return array of components. If limit is positive only limit number of components is returned. If limit is negative all components except the last abs(limit) are returned. */ 1013PHP_FUNCTION(explode) 1014{ 1015 char *str, *delim; 1016 int str_len = 0, delim_len = 0; 1017 long limit = LONG_MAX; /* No limit */ 1018 zval zdelim, zstr; 1019 1020 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|l", &delim, &delim_len, &str, &str_len, &limit) == FAILURE) { 1021 return; 1022 } 1023 1024 if (delim_len == 0) { 1025 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty delimiter"); 1026 RETURN_FALSE; 1027 } 1028 1029 array_init(return_value); 1030 1031 if (str_len == 0) { 1032 if (limit >= 0) { 1033 add_next_index_stringl(return_value, "", sizeof("") - 1, 1); 1034 } 1035 return; 1036 } 1037 1038 ZVAL_STRINGL(&zstr, str, str_len, 0); 1039 ZVAL_STRINGL(&zdelim, delim, delim_len, 0); 1040 if (limit > 1) { 1041 php_explode(&zdelim, &zstr, return_value, limit); 1042 } else if (limit < 0) { 1043 php_explode_negative_limit(&zdelim, &zstr, return_value, limit); 1044 } else { 1045 add_index_stringl(return_value, 0, str, str_len, 1); 1046 } 1047} 1048/* }}} */ 1049 1050/* {{{ proto string join(array src, string glue) 1051 An alias for implode */ 1052/* }}} */ 1053 1054/* {{{ php_implode 1055 */ 1056PHPAPI void php_implode(zval *delim, zval *arr, zval *return_value TSRMLS_DC) 1057{ 1058 zval **tmp; 1059 HashPosition pos; 1060 smart_str implstr = {0}; 1061 int numelems, i = 0; 1062 zval tmp_val; 1063 int str_len; 1064 1065 numelems = zend_hash_num_elements(Z_ARRVAL_P(arr)); 1066 1067 if (numelems == 0) { 1068 RETURN_EMPTY_STRING(); 1069 } 1070 1071 zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(arr), &pos); 1072 1073 while (zend_hash_get_current_data_ex(Z_ARRVAL_P(arr), (void **) &tmp, &pos) == SUCCESS) { 1074 switch ((*tmp)->type) { 1075 case IS_STRING: 1076 smart_str_appendl(&implstr, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp)); 1077 break; 1078 1079 case IS_LONG: { 1080 char stmp[MAX_LENGTH_OF_LONG + 1]; 1081 str_len = slprintf(stmp, sizeof(stmp), "%ld", Z_LVAL_PP(tmp)); 1082 smart_str_appendl(&implstr, stmp, str_len); 1083 } 1084 break; 1085 1086 case IS_BOOL: 1087 if (Z_LVAL_PP(tmp) == 1) { 1088 smart_str_appendl(&implstr, "1", sizeof("1")-1); 1089 } 1090 break; 1091 1092 case IS_NULL: 1093 break; 1094 1095 case IS_DOUBLE: { 1096 char *stmp; 1097 str_len = spprintf(&stmp, 0, "%.*G", (int) EG(precision), Z_DVAL_PP(tmp)); 1098 smart_str_appendl(&implstr, stmp, str_len); 1099 efree(stmp); 1100 } 1101 break; 1102 1103 case IS_OBJECT: { 1104 int copy; 1105 zval expr; 1106 zend_make_printable_zval(*tmp, &expr, ©); 1107 smart_str_appendl(&implstr, Z_STRVAL(expr), Z_STRLEN(expr)); 1108 if (copy) { 1109 zval_dtor(&expr); 1110 } 1111 } 1112 break; 1113 1114 default: 1115 tmp_val = **tmp; 1116 zval_copy_ctor(&tmp_val); 1117 convert_to_string(&tmp_val); 1118 smart_str_appendl(&implstr, Z_STRVAL(tmp_val), Z_STRLEN(tmp_val)); 1119 zval_dtor(&tmp_val); 1120 break; 1121 1122 } 1123 1124 if (++i != numelems) { 1125 smart_str_appendl(&implstr, Z_STRVAL_P(delim), Z_STRLEN_P(delim)); 1126 } 1127 zend_hash_move_forward_ex(Z_ARRVAL_P(arr), &pos); 1128 } 1129 smart_str_0(&implstr); 1130 1131 if (implstr.len) { 1132 RETURN_STRINGL(implstr.c, implstr.len, 0); 1133 } else { 1134 smart_str_free(&implstr); 1135 RETURN_EMPTY_STRING(); 1136 } 1137} 1138/* }}} */ 1139 1140/* {{{ proto string implode([string glue,] array pieces) 1141 Joins array elements placing glue string between items and return one string */ 1142PHP_FUNCTION(implode) 1143{ 1144 zval **arg1 = NULL, **arg2 = NULL, *delim, *arr; 1145 1146 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|Z", &arg1, &arg2) == FAILURE) { 1147 return; 1148 } 1149 1150 if (arg2 == NULL) { 1151 if (Z_TYPE_PP(arg1) != IS_ARRAY) { 1152 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument must be an array"); 1153 return; 1154 } 1155 1156 MAKE_STD_ZVAL(delim); 1157#define _IMPL_EMPTY "" 1158 ZVAL_STRINGL(delim, _IMPL_EMPTY, sizeof(_IMPL_EMPTY) - 1, 0); 1159 1160 SEPARATE_ZVAL(arg1); 1161 arr = *arg1; 1162 } else { 1163 if (Z_TYPE_PP(arg1) == IS_ARRAY) { 1164 arr = *arg1; 1165 convert_to_string_ex(arg2); 1166 delim = *arg2; 1167 } else if (Z_TYPE_PP(arg2) == IS_ARRAY) { 1168 arr = *arg2; 1169 convert_to_string_ex(arg1); 1170 delim = *arg1; 1171 } else { 1172 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid arguments passed"); 1173 return; 1174 } 1175 } 1176 1177 php_implode(delim, arr, return_value TSRMLS_CC); 1178 1179 if (arg2 == NULL) { 1180 FREE_ZVAL(delim); 1181 } 1182} 1183/* }}} */ 1184 1185#define STRTOK_TABLE(p) BG(strtok_table)[(unsigned char) *p] 1186 1187/* {{{ proto string strtok([string str,] string token) 1188 Tokenize a string */ 1189PHP_FUNCTION(strtok) 1190{ 1191 char *str, *tok = NULL; 1192 int str_len, tok_len = 0; 1193 zval *zv; 1194 1195 char *token; 1196 char *token_end; 1197 char *p; 1198 char *pe; 1199 int skipped = 0; 1200 1201 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &str, &str_len, &tok, &tok_len) == FAILURE) { 1202 return; 1203 } 1204 1205 if (ZEND_NUM_ARGS() == 1) { 1206 tok = str; 1207 tok_len = str_len; 1208 } else { 1209 if (BG(strtok_zval)) { 1210 zval_ptr_dtor(&BG(strtok_zval)); 1211 } 1212 MAKE_STD_ZVAL(zv); 1213 ZVAL_STRINGL(zv, str, str_len, 1); 1214 1215 BG(strtok_zval) = zv; 1216 BG(strtok_last) = BG(strtok_string) = Z_STRVAL_P(zv); 1217 BG(strtok_len) = str_len; 1218 } 1219 1220 p = BG(strtok_last); /* Where we start to search */ 1221 pe = BG(strtok_string) + BG(strtok_len); 1222 1223 if (!p || p >= pe) { 1224 RETURN_FALSE; 1225 } 1226 1227 token = tok; 1228 token_end = token + tok_len; 1229 1230 while (token < token_end) { 1231 STRTOK_TABLE(token++) = 1; 1232 } 1233 1234 /* Skip leading delimiters */ 1235 while (STRTOK_TABLE(p)) { 1236 if (++p >= pe) { 1237 /* no other chars left */ 1238 BG(strtok_last) = NULL; 1239 RETVAL_FALSE; 1240 goto restore; 1241 } 1242 skipped++; 1243 } 1244 1245 /* We know at this place that *p is no delimiter, so skip it */ 1246 while (++p < pe) { 1247 if (STRTOK_TABLE(p)) { 1248 goto return_token; 1249 } 1250 } 1251 1252 if (p - BG(strtok_last)) { 1253return_token: 1254 RETVAL_STRINGL(BG(strtok_last) + skipped, (p - BG(strtok_last)) - skipped, 1); 1255 BG(strtok_last) = p + 1; 1256 } else { 1257 RETVAL_FALSE; 1258 BG(strtok_last) = NULL; 1259 } 1260 1261 /* Restore table -- usually faster then memset'ing the table on every invocation */ 1262restore: 1263 token = tok; 1264 1265 while (token < token_end) { 1266 STRTOK_TABLE(token++) = 0; 1267 } 1268} 1269/* }}} */ 1270 1271/* {{{ php_strtoupper 1272 */ 1273PHPAPI char *php_strtoupper(char *s, size_t len) 1274{ 1275 unsigned char *c, *e; 1276 1277 c = (unsigned char *)s; 1278 e = (unsigned char *)c+len; 1279 1280 while (c < e) { 1281 *c = toupper(*c); 1282 c++; 1283 } 1284 return s; 1285} 1286/* }}} */ 1287 1288/* {{{ proto string strtoupper(string str) 1289 Makes a string uppercase */ 1290PHP_FUNCTION(strtoupper) 1291{ 1292 char *arg; 1293 int arglen; 1294 1295 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arglen) == FAILURE) { 1296 return; 1297 } 1298 1299 arg = estrndup(arg, arglen); 1300 php_strtoupper(arg, arglen); 1301 RETURN_STRINGL(arg, arglen, 0); 1302} 1303/* }}} */ 1304 1305/* {{{ php_strtolower 1306 */ 1307PHPAPI char *php_strtolower(char *s, size_t len) 1308{ 1309 unsigned char *c, *e; 1310 1311 c = (unsigned char *)s; 1312 e = c+len; 1313 1314 while (c < e) { 1315 *c = tolower(*c); 1316 c++; 1317 } 1318 return s; 1319} 1320/* }}} */ 1321 1322/* {{{ proto string strtolower(string str) 1323 Makes a string lowercase */ 1324PHP_FUNCTION(strtolower) 1325{ 1326 char *str; 1327 int arglen; 1328 1329 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &arglen) == FAILURE) { 1330 return; 1331 } 1332 1333 str = estrndup(str, arglen); 1334 php_strtolower(str, arglen); 1335 RETURN_STRINGL(str, arglen, 0); 1336} 1337/* }}} */ 1338 1339/* {{{ php_basename 1340 */ 1341PHPAPI void php_basename(char *s, size_t len, char *suffix, size_t sufflen, char **p_ret, size_t *p_len TSRMLS_DC) 1342{ 1343 char *ret = NULL, *c, *comp, *cend; 1344 size_t inc_len, cnt; 1345 int state; 1346 1347 c = comp = cend = s; 1348 cnt = len; 1349 state = 0; 1350 while (cnt > 0) { 1351 inc_len = (*c == '\0' ? 1: php_mblen(c, cnt)); 1352 1353 switch (inc_len) { 1354 case -2: 1355 case -1: 1356 inc_len = 1; 1357 php_mblen(NULL, 0); 1358 break; 1359 case 0: 1360 goto quit_loop; 1361 case 1: 1362#if defined(PHP_WIN32) || defined(NETWARE) 1363 if (*c == '/' || *c == '\\') { 1364#else 1365 if (*c == '/') { 1366#endif 1367 if (state == 1) { 1368 state = 0; 1369 cend = c; 1370 } 1371 } else { 1372 if (state == 0) { 1373 comp = c; 1374 state = 1; 1375 } 1376 } 1377 break; 1378 default: 1379 if (state == 0) { 1380 comp = c; 1381 state = 1; 1382 } 1383 break; 1384 } 1385 c += inc_len; 1386 cnt -= inc_len; 1387 } 1388 1389quit_loop: 1390 if (state == 1) { 1391 cend = c; 1392 } 1393 if (suffix != NULL && sufflen < (uint)(cend - comp) && 1394 memcmp(cend - sufflen, suffix, sufflen) == 0) { 1395 cend -= sufflen; 1396 } 1397 1398 len = cend - comp; 1399 1400 if (p_ret) { 1401 ret = emalloc(len + 1); 1402 memcpy(ret, comp, len); 1403 ret[len] = '\0'; 1404 *p_ret = ret; 1405 } 1406 if (p_len) { 1407 *p_len = len; 1408 } 1409} 1410/* }}} */ 1411 1412/* {{{ proto string basename(string path [, string suffix]) 1413 Returns the filename component of the path */ 1414PHP_FUNCTION(basename) 1415{ 1416 char *string, *suffix = NULL, *ret; 1417 int string_len, suffix_len = 0; 1418 size_t ret_len; 1419 1420 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &string, &string_len, &suffix, &suffix_len) == FAILURE) { 1421 return; 1422 } 1423 1424 php_basename(string, string_len, suffix, suffix_len, &ret, &ret_len TSRMLS_CC); 1425 RETURN_STRINGL(ret, (int)ret_len, 0); 1426} 1427/* }}} */ 1428 1429/* {{{ php_dirname 1430 Returns directory name component of path */ 1431PHPAPI size_t php_dirname(char *path, size_t len) 1432{ 1433 return zend_dirname(path, len); 1434} 1435/* }}} */ 1436 1437/* {{{ proto string dirname(string path) 1438 Returns the directory name component of the path */ 1439PHP_FUNCTION(dirname) 1440{ 1441 char *str; 1442 char *ret; 1443 int str_len; 1444 size_t ret_len; 1445 1446 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) { 1447 return; 1448 } 1449 1450 ret = estrndup(str, str_len); 1451 ret_len = php_dirname(ret, str_len); 1452 1453 RETURN_STRINGL(ret, ret_len, 0); 1454} 1455/* }}} */ 1456 1457/* {{{ proto array pathinfo(string path[, int options]) 1458 Returns information about a certain string */ 1459PHP_FUNCTION(pathinfo) 1460{ 1461 zval *tmp; 1462 char *path, *ret = NULL; 1463 int path_len, have_basename; 1464 size_t ret_len; 1465 long opt = PHP_PATHINFO_ALL; 1466 1467 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &path, &path_len, &opt) == FAILURE) { 1468 return; 1469 } 1470 1471 have_basename = ((opt & PHP_PATHINFO_BASENAME) == PHP_PATHINFO_BASENAME); 1472 1473 MAKE_STD_ZVAL(tmp); 1474 array_init(tmp); 1475 1476 if ((opt & PHP_PATHINFO_DIRNAME) == PHP_PATHINFO_DIRNAME) { 1477 ret = estrndup(path, path_len); 1478 php_dirname(ret, path_len); 1479 if (*ret) { 1480 add_assoc_string(tmp, "dirname", ret, 1); 1481 } 1482 efree(ret); 1483 ret = NULL; 1484 } 1485 1486 if (have_basename) { 1487 php_basename(path, path_len, NULL, 0, &ret, &ret_len TSRMLS_CC); 1488 add_assoc_stringl(tmp, "basename", ret, ret_len, 0); 1489 } 1490 1491 if ((opt & PHP_PATHINFO_EXTENSION) == PHP_PATHINFO_EXTENSION) { 1492 char *p; 1493 int idx; 1494 1495 if (!have_basename) { 1496 php_basename(path, path_len, NULL, 0, &ret, &ret_len TSRMLS_CC); 1497 } 1498 1499 p = zend_memrchr(ret, '.', ret_len); 1500 1501 if (p) { 1502 idx = p - ret; 1503 add_assoc_stringl(tmp, "extension", ret + idx + 1, ret_len - idx - 1, 1); 1504 } 1505 } 1506 1507 if ((opt & PHP_PATHINFO_FILENAME) == PHP_PATHINFO_FILENAME) { 1508 char *p; 1509 int idx; 1510 1511 /* Have we alrady looked up the basename? */ 1512 if (!have_basename && !ret) { 1513 php_basename(path, path_len, NULL, 0, &ret, &ret_len TSRMLS_CC); 1514 } 1515 1516 p = zend_memrchr(ret, '.', ret_len); 1517 1518 idx = p ? (p - ret) : ret_len; 1519 add_assoc_stringl(tmp, "filename", ret, idx, 1); 1520 } 1521 1522 if (!have_basename && ret) { 1523 efree(ret); 1524 } 1525 1526 if (opt == PHP_PATHINFO_ALL) { 1527 RETURN_ZVAL(tmp, 0, 1); 1528 } else { 1529 zval **element; 1530 if (zend_hash_get_current_data(Z_ARRVAL_P(tmp), (void **) &element) == SUCCESS) { 1531 RETVAL_ZVAL(*element, 1, 0); 1532 } else { 1533 ZVAL_EMPTY_STRING(return_value); 1534 } 1535 } 1536 1537 zval_ptr_dtor(&tmp); 1538} 1539/* }}} */ 1540 1541/* {{{ php_stristr 1542 case insensitve strstr */ 1543PHPAPI char *php_stristr(char *s, char *t, size_t s_len, size_t t_len) 1544{ 1545 php_strtolower(s, s_len); 1546 php_strtolower(t, t_len); 1547 return php_memnstr(s, t, t_len, s + s_len); 1548} 1549/* }}} */ 1550 1551/* {{{ php_strspn 1552 */ 1553PHPAPI size_t php_strspn(char *s1, char *s2, char *s1_end, char *s2_end) 1554{ 1555 register const char *p = s1, *spanp; 1556 register char c = *p; 1557 1558cont: 1559 for (spanp = s2; p != s1_end && spanp != s2_end;) { 1560 if (*spanp++ == c) { 1561 c = *(++p); 1562 goto cont; 1563 } 1564 } 1565 return (p - s1); 1566} 1567/* }}} */ 1568 1569/* {{{ php_strcspn 1570 */ 1571PHPAPI size_t php_strcspn(char *s1, char *s2, char *s1_end, char *s2_end) 1572{ 1573 register const char *p, *spanp; 1574 register char c = *s1; 1575 1576 for (p = s1;;) { 1577 spanp = s2; 1578 do { 1579 if (*spanp == c || p == s1_end) { 1580 return p - s1; 1581 } 1582 } while (spanp++ < (s2_end - 1)); 1583 c = *++p; 1584 } 1585 /* NOTREACHED */ 1586} 1587/* }}} */ 1588 1589/* {{{ php_needle_char 1590 */ 1591static int php_needle_char(zval *needle, char *target TSRMLS_DC) 1592{ 1593 switch (Z_TYPE_P(needle)) { 1594 case IS_LONG: 1595 case IS_BOOL: 1596 *target = (char)Z_LVAL_P(needle); 1597 return SUCCESS; 1598 case IS_NULL: 1599 *target = '\0'; 1600 return SUCCESS; 1601 case IS_DOUBLE: 1602 *target = (char)(int)Z_DVAL_P(needle); 1603 return SUCCESS; 1604 case IS_OBJECT: 1605 { 1606 zval holder = *needle; 1607 zval_copy_ctor(&(holder)); 1608 convert_to_long(&(holder)); 1609 if(Z_TYPE(holder) != IS_LONG) { 1610 return FAILURE; 1611 } 1612 *target = (char)Z_LVAL(holder); 1613 return SUCCESS; 1614 } 1615 default: { 1616 php_error_docref(NULL TSRMLS_CC, E_WARNING, "needle is not a string or an integer"); 1617 return FAILURE; 1618 } 1619 } 1620} 1621/* }}} */ 1622 1623/* {{{ proto string stristr(string haystack, string needle[, bool part]) 1624 Finds first occurrence of a string within another, case insensitive */ 1625PHP_FUNCTION(stristr) 1626{ 1627 zval *needle; 1628 char *haystack; 1629 int haystack_len; 1630 char *found = NULL; 1631 int found_offset; 1632 char *haystack_dup; 1633 char needle_char[2]; 1634 zend_bool part = 0; 1635 1636 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|b", &haystack, &haystack_len, &needle, &part) == FAILURE) { 1637 return; 1638 } 1639 1640 haystack_dup = estrndup(haystack, haystack_len); 1641 1642 if (Z_TYPE_P(needle) == IS_STRING) { 1643 char *orig_needle; 1644 if (!Z_STRLEN_P(needle)) { 1645 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty delimiter"); 1646 efree(haystack_dup); 1647 RETURN_FALSE; 1648 } 1649 orig_needle = estrndup(Z_STRVAL_P(needle), Z_STRLEN_P(needle)); 1650 found = php_stristr(haystack_dup, orig_needle, haystack_len, Z_STRLEN_P(needle)); 1651 efree(orig_needle); 1652 } else { 1653 if (php_needle_char(needle, needle_char TSRMLS_CC) != SUCCESS) { 1654 efree(haystack_dup); 1655 RETURN_FALSE; 1656 } 1657 needle_char[1] = 0; 1658 1659 found = php_stristr(haystack_dup, needle_char, haystack_len, 1); 1660 } 1661 1662 if (found) { 1663 found_offset = found - haystack_dup; 1664 if (part) { 1665 RETVAL_STRINGL(haystack, found_offset, 1); 1666 } else { 1667 RETVAL_STRINGL(haystack + found_offset, haystack_len - found_offset, 1); 1668 } 1669 } else { 1670 RETVAL_FALSE; 1671 } 1672 1673 efree(haystack_dup); 1674} 1675/* }}} */ 1676 1677/* {{{ proto string strstr(string haystack, string needle[, bool part]) 1678 Finds first occurrence of a string within another */ 1679PHP_FUNCTION(strstr) 1680{ 1681 zval *needle; 1682 char *haystack; 1683 int haystack_len; 1684 char *found = NULL; 1685 char needle_char[2]; 1686 long found_offset; 1687 zend_bool part = 0; 1688 1689 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|b", &haystack, &haystack_len, &needle, &part) == FAILURE) { 1690 return; 1691 } 1692 1693 if (Z_TYPE_P(needle) == IS_STRING) { 1694 if (!Z_STRLEN_P(needle)) { 1695 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty delimiter"); 1696 RETURN_FALSE; 1697 } 1698 1699 found = php_memnstr(haystack, Z_STRVAL_P(needle), Z_STRLEN_P(needle), haystack + haystack_len); 1700 } else { 1701 if (php_needle_char(needle, needle_char TSRMLS_CC) != SUCCESS) { 1702 RETURN_FALSE; 1703 } 1704 needle_char[1] = 0; 1705 1706 found = php_memnstr(haystack, needle_char, 1, haystack + haystack_len); 1707 } 1708 1709 if (found) { 1710 found_offset = found - haystack; 1711 if (part) { 1712 RETURN_STRINGL(haystack, found_offset, 1); 1713 } else { 1714 RETURN_STRINGL(found, haystack_len - found_offset, 1); 1715 } 1716 } 1717 RETURN_FALSE; 1718} 1719/* }}} */ 1720 1721/* {{{ proto string strchr(string haystack, string needle) 1722 An alias for strstr */ 1723/* }}} */ 1724 1725/* {{{ proto int strpos(string haystack, string needle [, int offset]) 1726 Finds position of first occurrence of a string within another */ 1727PHP_FUNCTION(strpos) 1728{ 1729 zval *needle; 1730 char *haystack; 1731 char *found = NULL; 1732 char needle_char[2]; 1733 long offset = 0; 1734 int haystack_len; 1735 1736 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|l", &haystack, &haystack_len, &needle, &offset) == FAILURE) { 1737 return; 1738 } 1739 1740 if (offset < 0 || offset > haystack_len) { 1741 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset not contained in string"); 1742 RETURN_FALSE; 1743 } 1744 1745 if (Z_TYPE_P(needle) == IS_STRING) { 1746 if (!Z_STRLEN_P(needle)) { 1747 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty needle"); 1748 RETURN_FALSE; 1749 } 1750 1751 found = php_memnstr(haystack + offset, 1752 Z_STRVAL_P(needle), 1753 Z_STRLEN_P(needle), 1754 haystack + haystack_len); 1755 } else { 1756 if (php_needle_char(needle, needle_char TSRMLS_CC) != SUCCESS) { 1757 RETURN_FALSE; 1758 } 1759 needle_char[1] = 0; 1760 1761 found = php_memnstr(haystack + offset, 1762 needle_char, 1763 1, 1764 haystack + haystack_len); 1765 } 1766 1767 if (found) { 1768 RETURN_LONG(found - haystack); 1769 } else { 1770 RETURN_FALSE; 1771 } 1772} 1773/* }}} */ 1774 1775/* {{{ proto int stripos(string haystack, string needle [, int offset]) 1776 Finds position of first occurrence of a string within another, case insensitive */ 1777PHP_FUNCTION(stripos) 1778{ 1779 char *found = NULL; 1780 char *haystack; 1781 int haystack_len; 1782 long offset = 0; 1783 char *needle_dup = NULL, *haystack_dup; 1784 char needle_char[2]; 1785 zval *needle; 1786 1787 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|l", &haystack, &haystack_len, &needle, &offset) == FAILURE) { 1788 return; 1789 } 1790 1791 if (offset < 0 || offset > haystack_len) { 1792 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset not contained in string"); 1793 RETURN_FALSE; 1794 } 1795 1796 if (haystack_len == 0) { 1797 RETURN_FALSE; 1798 } 1799 1800 haystack_dup = estrndup(haystack, haystack_len); 1801 php_strtolower(haystack_dup, haystack_len); 1802 1803 if (Z_TYPE_P(needle) == IS_STRING) { 1804 if (Z_STRLEN_P(needle) == 0 || Z_STRLEN_P(needle) > haystack_len) { 1805 efree(haystack_dup); 1806 RETURN_FALSE; 1807 } 1808 1809 needle_dup = estrndup(Z_STRVAL_P(needle), Z_STRLEN_P(needle)); 1810 php_strtolower(needle_dup, Z_STRLEN_P(needle)); 1811 found = php_memnstr(haystack_dup + offset, needle_dup, Z_STRLEN_P(needle), haystack_dup + haystack_len); 1812 } else { 1813 if (php_needle_char(needle, needle_char TSRMLS_CC) != SUCCESS) { 1814 efree(haystack_dup); 1815 RETURN_FALSE; 1816 } 1817 needle_char[0] = tolower(needle_char[0]); 1818 needle_char[1] = '\0'; 1819 found = php_memnstr(haystack_dup + offset, 1820 needle_char, 1821 sizeof(needle_char) - 1, 1822 haystack_dup + haystack_len); 1823 } 1824 1825 efree(haystack_dup); 1826 if (needle_dup) { 1827 efree(needle_dup); 1828 } 1829 1830 if (found) { 1831 RETURN_LONG(found - haystack_dup); 1832 } else { 1833 RETURN_FALSE; 1834 } 1835} 1836/* }}} */ 1837 1838/* {{{ proto int strrpos(string haystack, string needle [, int offset]) 1839 Finds position of last occurrence of a string within another string */ 1840PHP_FUNCTION(strrpos) 1841{ 1842 zval *zneedle; 1843 char *needle, *haystack; 1844 int needle_len, haystack_len; 1845 long offset = 0; 1846 char *p, *e, ord_needle[2]; 1847 1848 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|l", &haystack, &haystack_len, &zneedle, &offset) == FAILURE) { 1849 RETURN_FALSE; 1850 } 1851 1852 if (Z_TYPE_P(zneedle) == IS_STRING) { 1853 needle = Z_STRVAL_P(zneedle); 1854 needle_len = Z_STRLEN_P(zneedle); 1855 } else { 1856 if (php_needle_char(zneedle, ord_needle TSRMLS_CC) != SUCCESS) { 1857 RETURN_FALSE; 1858 } 1859 ord_needle[1] = '\0'; 1860 needle = ord_needle; 1861 needle_len = 1; 1862 } 1863 1864 if ((haystack_len == 0) || (needle_len == 0)) { 1865 RETURN_FALSE; 1866 } 1867 1868 if (offset >= 0) { 1869 if (offset > haystack_len) { 1870 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset is greater than the length of haystack string"); 1871 RETURN_FALSE; 1872 } 1873 p = haystack + offset; 1874 e = haystack + haystack_len - needle_len; 1875 } else { 1876 if (offset < -INT_MAX || -offset > haystack_len) { 1877 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset is greater than the length of haystack string"); 1878 RETURN_FALSE; 1879 } 1880 1881 p = haystack; 1882 if (needle_len > -offset) { 1883 e = haystack + haystack_len - needle_len; 1884 } else { 1885 e = haystack + haystack_len + offset; 1886 } 1887 } 1888 1889 if (needle_len == 1) { 1890 /* Single character search can shortcut memcmps */ 1891 while (e >= p) { 1892 if (*e == *needle) { 1893 RETURN_LONG(e - p + (offset > 0 ? offset : 0)); 1894 } 1895 e--; 1896 } 1897 RETURN_FALSE; 1898 } 1899 1900 while (e >= p) { 1901 if (memcmp(e, needle, needle_len) == 0) { 1902 RETURN_LONG(e - p + (offset > 0 ? offset : 0)); 1903 } 1904 e--; 1905 } 1906 1907 RETURN_FALSE; 1908} 1909/* }}} */ 1910 1911/* {{{ proto int strripos(string haystack, string needle [, int offset]) 1912 Finds position of last occurrence of a string within another string */ 1913PHP_FUNCTION(strripos) 1914{ 1915 zval *zneedle; 1916 char *needle, *haystack; 1917 int needle_len, haystack_len; 1918 long offset = 0; 1919 char *p, *e, ord_needle[2]; 1920 char *needle_dup, *haystack_dup; 1921 1922 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|l", &haystack, &haystack_len, &zneedle, &offset) == FAILURE) { 1923 RETURN_FALSE; 1924 } 1925 1926 if (Z_TYPE_P(zneedle) == IS_STRING) { 1927 needle = Z_STRVAL_P(zneedle); 1928 needle_len = Z_STRLEN_P(zneedle); 1929 } else { 1930 if (php_needle_char(zneedle, ord_needle TSRMLS_CC) != SUCCESS) { 1931 RETURN_FALSE; 1932 } 1933 ord_needle[1] = '\0'; 1934 needle = ord_needle; 1935 needle_len = 1; 1936 } 1937 1938 if ((haystack_len == 0) || (needle_len == 0)) { 1939 RETURN_FALSE; 1940 } 1941 1942 if (needle_len == 1) { 1943 /* Single character search can shortcut memcmps 1944 Can also avoid tolower emallocs */ 1945 if (offset >= 0) { 1946 if (offset > haystack_len) { 1947 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset is greater than the length of haystack string"); 1948 RETURN_FALSE; 1949 } 1950 p = haystack + offset; 1951 e = haystack + haystack_len - 1; 1952 } else { 1953 p = haystack; 1954 if (offset < -INT_MAX || -offset > haystack_len) { 1955 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset is greater than the length of haystack string"); 1956 RETURN_FALSE; 1957 } 1958 e = haystack + haystack_len + offset; 1959 } 1960 /* Borrow that ord_needle buffer to avoid repeatedly tolower()ing needle */ 1961 *ord_needle = tolower(*needle); 1962 while (e >= p) { 1963 if (tolower(*e) == *ord_needle) { 1964 RETURN_LONG(e - p + (offset > 0 ? offset : 0)); 1965 } 1966 e--; 1967 } 1968 RETURN_FALSE; 1969 } 1970 1971 needle_dup = estrndup(needle, needle_len); 1972 php_strtolower(needle_dup, needle_len); 1973 haystack_dup = estrndup(haystack, haystack_len); 1974 php_strtolower(haystack_dup, haystack_len); 1975 1976 if (offset >= 0) { 1977 if (offset > haystack_len) { 1978 efree(needle_dup); 1979 efree(haystack_dup); 1980 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset is greater than the length of haystack string"); 1981 RETURN_FALSE; 1982 } 1983 p = haystack_dup + offset; 1984 e = haystack_dup + haystack_len - needle_len; 1985 } else { 1986 if (offset < -INT_MAX || -offset > haystack_len) { 1987 efree(needle_dup); 1988 efree(haystack_dup); 1989 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset is greater than the length of haystack string"); 1990 RETURN_FALSE; 1991 } 1992 p = haystack_dup; 1993 if (needle_len > -offset) { 1994 e = haystack_dup + haystack_len - needle_len; 1995 } else { 1996 e = haystack_dup + haystack_len + offset; 1997 } 1998 } 1999 2000 while (e >= p) { 2001 if (memcmp(e, needle_dup, needle_len) == 0) { 2002 efree(haystack_dup); 2003 efree(needle_dup); 2004 RETURN_LONG(e - p + (offset > 0 ? offset : 0)); 2005 } 2006 e--; 2007 } 2008 2009 efree(haystack_dup); 2010 efree(needle_dup); 2011 RETURN_FALSE; 2012} 2013/* }}} */ 2014 2015/* {{{ proto string strrchr(string haystack, string needle) 2016 Finds the last occurrence of a character in a string within another */ 2017PHP_FUNCTION(strrchr) 2018{ 2019 zval *needle; 2020 char *haystack; 2021 char *found = NULL; 2022 long found_offset; 2023 int haystack_len; 2024 2025 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &haystack, &haystack_len, &needle) == FAILURE) { 2026 return; 2027 } 2028 2029 if (Z_TYPE_P(needle) == IS_STRING) { 2030 found = zend_memrchr(haystack, *Z_STRVAL_P(needle), haystack_len); 2031 } else { 2032 char needle_chr; 2033 if (php_needle_char(needle, &needle_chr TSRMLS_CC) != SUCCESS) { 2034 RETURN_FALSE; 2035 } 2036 2037 found = zend_memrchr(haystack, needle_chr, haystack_len); 2038 } 2039 2040 if (found) { 2041 found_offset = found - haystack; 2042 RETURN_STRINGL(found, haystack_len - found_offset, 1); 2043 } else { 2044 RETURN_FALSE; 2045 } 2046} 2047/* }}} */ 2048 2049/* {{{ php_chunk_split 2050 */ 2051static char *php_chunk_split(char *src, int srclen, char *end, int endlen, int chunklen, int *destlen) 2052{ 2053 char *dest; 2054 char *p, *q; 2055 int chunks; /* complete chunks! */ 2056 int restlen; 2057 int out_len; 2058 2059 chunks = srclen / chunklen; 2060 restlen = srclen - chunks * chunklen; /* srclen % chunklen */ 2061 2062 if(chunks > INT_MAX - 1) { 2063 return NULL; 2064 } 2065 out_len = chunks + 1; 2066 if(endlen !=0 && out_len > INT_MAX/endlen) { 2067 return NULL; 2068 } 2069 out_len *= endlen; 2070 if(out_len > INT_MAX - srclen - 1) { 2071 return NULL; 2072 } 2073 out_len += srclen + 1; 2074 2075 dest = safe_emalloc((int)out_len, sizeof(char), 0); 2076 2077 for (p = src, q = dest; p < (src + srclen - chunklen + 1); ) { 2078 memcpy(q, p, chunklen); 2079 q += chunklen; 2080 memcpy(q, end, endlen); 2081 q += endlen; 2082 p += chunklen; 2083 } 2084 2085 if (restlen) { 2086 memcpy(q, p, restlen); 2087 q += restlen; 2088 memcpy(q, end, endlen); 2089 q += endlen; 2090 } 2091 2092 *q = '\0'; 2093 if (destlen) { 2094 *destlen = q - dest; 2095 } 2096 2097 return(dest); 2098} 2099/* }}} */ 2100 2101/* {{{ proto string chunk_split(string str [, int chunklen [, string ending]]) 2102 Returns split line */ 2103PHP_FUNCTION(chunk_split) 2104{ 2105 char *str; 2106 char *result; 2107 char *end = "\r\n"; 2108 int endlen = 2; 2109 long chunklen = 76; 2110 int result_len; 2111 int str_len; 2112 2113 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ls", &str, &str_len, &chunklen, &end, &endlen) == FAILURE) { 2114 return; 2115 } 2116 2117 if (chunklen <= 0) { 2118 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Chunk length should be greater than zero"); 2119 RETURN_FALSE; 2120 } 2121 2122 if (chunklen > str_len) { 2123 /* to maintain BC, we must return original string + ending */ 2124 result_len = endlen + str_len; 2125 result = emalloc(result_len + 1); 2126 memcpy(result, str, str_len); 2127 memcpy(result + str_len, end, endlen); 2128 result[result_len] = '\0'; 2129 RETURN_STRINGL(result, result_len, 0); 2130 } 2131 2132 if (!str_len) { 2133 RETURN_EMPTY_STRING(); 2134 } 2135 2136 result = php_chunk_split(str, str_len, end, endlen, chunklen, &result_len); 2137 2138 if (result) { 2139 RETURN_STRINGL(result, result_len, 0); 2140 } else { 2141 RETURN_FALSE; 2142 } 2143} 2144/* }}} */ 2145 2146/* {{{ proto string substr(string str, int start [, int length]) 2147 Returns part of a string */ 2148PHP_FUNCTION(substr) 2149{ 2150 char *str; 2151 long l = 0, f; 2152 int str_len; 2153 int argc = ZEND_NUM_ARGS(); 2154 2155 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|l", &str, &str_len, &f, &l) == FAILURE) { 2156 return; 2157 } 2158 2159 if (argc > 2) { 2160 if ((l < 0 && -l > str_len)) { 2161 RETURN_FALSE; 2162 } else if (l > str_len) { 2163 l = str_len; 2164 } 2165 } else { 2166 l = str_len; 2167 } 2168 2169 if (f > str_len) { 2170 RETURN_FALSE; 2171 } else if (f < 0 && -f > str_len) { 2172 f = 0; 2173 } 2174 2175 if (l < 0 && (l + str_len - f) < 0) { 2176 RETURN_FALSE; 2177 } 2178 2179 /* if "from" position is negative, count start position from the end 2180 * of the string 2181 */ 2182 if (f < 0) { 2183 f = str_len + f; 2184 if (f < 0) { 2185 f = 0; 2186 } 2187 } 2188 2189 /* if "length" position is negative, set it to the length 2190 * needed to stop that many chars from the end of the string 2191 */ 2192 if (l < 0) { 2193 l = (str_len - f) + l; 2194 if (l < 0) { 2195 l = 0; 2196 } 2197 } 2198 2199 if (f >= str_len) { 2200 RETURN_FALSE; 2201 } 2202 2203 if ((f + l) > str_len) { 2204 l = str_len - f; 2205 } 2206 2207 RETURN_STRINGL(str + f, l, 1); 2208} 2209/* }}} */ 2210 2211/* {{{ proto mixed substr_replace(mixed str, mixed repl, mixed start [, mixed length]) 2212 Replaces part of a string with another string */ 2213PHP_FUNCTION(substr_replace) 2214{ 2215 zval **str; 2216 zval **from; 2217 zval **len = NULL; 2218 zval **repl; 2219 char *result; 2220 int result_len; 2221 int l = 0; 2222 int f; 2223 int argc = ZEND_NUM_ARGS(); 2224 2225 HashPosition pos_str, pos_from, pos_repl, pos_len; 2226 zval **tmp_str = NULL, **tmp_from = NULL, **tmp_repl = NULL, **tmp_len= NULL; 2227 2228 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZZ|Z", &str, &repl, &from, &len) == FAILURE) { 2229 return; 2230 } 2231 2232 if (Z_TYPE_PP(str) != IS_ARRAY) { 2233 if (Z_ISREF_PP(str)) { 2234 SEPARATE_ZVAL(str); 2235 } 2236 convert_to_string_ex(str); 2237 } 2238 if (Z_TYPE_PP(repl) != IS_ARRAY) { 2239 if (Z_ISREF_PP(repl)) { 2240 SEPARATE_ZVAL(repl); 2241 } 2242 convert_to_string_ex(repl); 2243 } 2244 if (Z_TYPE_PP(from) != IS_ARRAY) { 2245 if (Z_ISREF_PP(from)) { 2246 SEPARATE_ZVAL(from); 2247 } 2248 convert_to_long_ex(from); 2249 } 2250 2251 if (argc > 3) { 2252 SEPARATE_ZVAL(len); 2253 if (Z_TYPE_PP(len) != IS_ARRAY) { 2254 convert_to_long_ex(len); 2255 l = Z_LVAL_PP(len); 2256 } 2257 } else { 2258 if (Z_TYPE_PP(str) != IS_ARRAY) { 2259 l = Z_STRLEN_PP(str); 2260 } 2261 } 2262 2263 if (Z_TYPE_PP(str) == IS_STRING) { 2264 if ( 2265 (argc == 3 && Z_TYPE_PP(from) == IS_ARRAY) || 2266 (argc == 4 && Z_TYPE_PP(from) != Z_TYPE_PP(len)) 2267 ) { 2268 php_error_docref(NULL TSRMLS_CC, E_WARNING, "'from' and 'len' should be of same type - numerical or array "); 2269 RETURN_STRINGL(Z_STRVAL_PP(str), Z_STRLEN_PP(str), 1); 2270 } 2271 if (argc == 4 && Z_TYPE_PP(from) == IS_ARRAY) { 2272 if (zend_hash_num_elements(Z_ARRVAL_PP(from)) != zend_hash_num_elements(Z_ARRVAL_PP(len))) { 2273 php_error_docref(NULL TSRMLS_CC, E_WARNING, "'from' and 'len' should have the same number of elements"); 2274 RETURN_STRINGL(Z_STRVAL_PP(str), Z_STRLEN_PP(str), 1); 2275 } 2276 } 2277 } 2278 2279 if (Z_TYPE_PP(str) != IS_ARRAY) { 2280 if (Z_TYPE_PP(from) != IS_ARRAY) { 2281 int repl_len = 0; 2282 2283 f = Z_LVAL_PP(from); 2284 2285 /* if "from" position is negative, count start position from the end 2286 * of the string 2287 */ 2288 if (f < 0) { 2289 f = Z_STRLEN_PP(str) + f; 2290 if (f < 0) { 2291 f = 0; 2292 } 2293 } else if (f > Z_STRLEN_PP(str)) { 2294 f = Z_STRLEN_PP(str); 2295 } 2296 /* if "length" position is negative, set it to the length 2297 * needed to stop that many chars from the end of the string 2298 */ 2299 if (l < 0) { 2300 l = (Z_STRLEN_PP(str) - f) + l; 2301 if (l < 0) { 2302 l = 0; 2303 } 2304 } 2305 2306 if (f > Z_STRLEN_PP(str) || (f < 0 && -f > Z_STRLEN_PP(str))) { 2307 RETURN_FALSE; 2308 } else if (l > Z_STRLEN_PP(str) || (l < 0 && -l > Z_STRLEN_PP(str))) { 2309 l = Z_STRLEN_PP(str); 2310 } 2311 2312 if ((f + l) > Z_STRLEN_PP(str)) { 2313 l = Z_STRLEN_PP(str) - f; 2314 } 2315 if (Z_TYPE_PP(repl) == IS_ARRAY) { 2316 zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(repl), &pos_repl); 2317 if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(repl), (void **) &tmp_repl, &pos_repl)) { 2318 convert_to_string_ex(tmp_repl); 2319 repl_len = Z_STRLEN_PP(tmp_repl); 2320 } 2321 } else { 2322 repl_len = Z_STRLEN_PP(repl); 2323 } 2324 result_len = Z_STRLEN_PP(str) - l + repl_len; 2325 result = emalloc(result_len + 1); 2326 2327 memcpy(result, Z_STRVAL_PP(str), f); 2328 if (repl_len) { 2329 memcpy((result + f), (Z_TYPE_PP(repl) == IS_ARRAY ? Z_STRVAL_PP(tmp_repl) : Z_STRVAL_PP(repl)), repl_len); 2330 } 2331 memcpy((result + f + repl_len), Z_STRVAL_PP(str) + f + l, Z_STRLEN_PP(str) - f - l); 2332 result[result_len] = '\0'; 2333 RETURN_STRINGL(result, result_len, 0); 2334 } else { 2335 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Functionality of 'from' and 'len' as arrays is not implemented"); 2336 RETURN_STRINGL(Z_STRVAL_PP(str), Z_STRLEN_PP(str), 1); 2337 } 2338 } else { /* str is array of strings */ 2339 char *str_index = NULL; 2340 uint str_index_len; 2341 ulong num_index; 2342 2343 array_init(return_value); 2344 2345 if (Z_TYPE_PP(from) == IS_ARRAY) { 2346 zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(from), &pos_from); 2347 } 2348 2349 if (argc > 3 && Z_TYPE_PP(len) == IS_ARRAY) { 2350 zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(len), &pos_len); 2351 } 2352 2353 if (Z_TYPE_PP(repl) == IS_ARRAY) { 2354 zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(repl), &pos_repl); 2355 } 2356 2357 zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(str), &pos_str); 2358 while (zend_hash_get_current_data_ex(Z_ARRVAL_PP(str), (void **) &tmp_str, &pos_str) == SUCCESS) { 2359 zval *orig_str; 2360 zval dummy; 2361 if(Z_TYPE_PP(tmp_str) != IS_STRING) { 2362 dummy = **tmp_str; 2363 orig_str = &dummy; 2364 zval_copy_ctor(orig_str); 2365 convert_to_string(orig_str); 2366 } else { 2367 orig_str = *tmp_str; 2368 } 2369 2370 if (Z_TYPE_PP(from) == IS_ARRAY) { 2371 if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(from), (void **) &tmp_from, &pos_from)) { 2372 if(Z_TYPE_PP(tmp_from) != IS_LONG) { 2373 zval dummy = **tmp_from; 2374 zval_copy_ctor(&dummy); 2375 convert_to_long(&dummy); 2376 f = Z_LVAL(dummy); 2377 } else { 2378 f = Z_LVAL_PP(tmp_from); 2379 } 2380 2381 if (f < 0) { 2382 f = Z_STRLEN_P(orig_str) + f; 2383 if (f < 0) { 2384 f = 0; 2385 } 2386 } else if (f > Z_STRLEN_P(orig_str)) { 2387 f = Z_STRLEN_P(orig_str); 2388 } 2389 zend_hash_move_forward_ex(Z_ARRVAL_PP(from), &pos_from); 2390 } else { 2391 f = 0; 2392 } 2393 } else { 2394 f = Z_LVAL_PP(from); 2395 if (f < 0) { 2396 f = Z_STRLEN_P(orig_str) + f; 2397 if (f < 0) { 2398 f = 0; 2399 } 2400 } else if (f > Z_STRLEN_P(orig_str)) { 2401 f = Z_STRLEN_P(orig_str); 2402 } 2403 } 2404 2405 if (argc > 3 && Z_TYPE_PP(len) == IS_ARRAY) { 2406 if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(len), (void **) &tmp_len, &pos_len)) { 2407 if(Z_TYPE_PP(tmp_len) != IS_LONG) { 2408 zval dummy = **tmp_len; 2409 zval_copy_ctor(&dummy); 2410 convert_to_long(&dummy); 2411 l = Z_LVAL(dummy); 2412 } else { 2413 l = Z_LVAL_PP(tmp_len); 2414 } 2415 zend_hash_move_forward_ex(Z_ARRVAL_PP(len), &pos_len); 2416 } else { 2417 l = Z_STRLEN_P(orig_str); 2418 } 2419 } else if (argc > 3) { 2420 l = Z_LVAL_PP(len); 2421 } else { 2422 l = Z_STRLEN_P(orig_str); 2423 } 2424 2425 if (l < 0) { 2426 l = (Z_STRLEN_P(orig_str) - f) + l; 2427 if (l < 0) { 2428 l = 0; 2429 } 2430 } 2431 2432 if ((f + l) > Z_STRLEN_P(orig_str)) { 2433 l = Z_STRLEN_P(orig_str) - f; 2434 } 2435 2436 result_len = Z_STRLEN_P(orig_str) - l; 2437 2438 if (Z_TYPE_PP(repl) == IS_ARRAY) { 2439 if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(repl), (void **) &tmp_repl, &pos_repl)) { 2440 zval *repl_str; 2441 zval zrepl; 2442 if(Z_TYPE_PP(tmp_repl) != IS_STRING) { 2443 zrepl = **tmp_repl; 2444 repl_str = &zrepl; 2445 zval_copy_ctor(repl_str); 2446 convert_to_string(repl_str); 2447 } else { 2448 repl_str = *tmp_repl; 2449 } 2450 2451 result_len += Z_STRLEN_P(repl_str); 2452 zend_hash_move_forward_ex(Z_ARRVAL_PP(repl), &pos_repl); 2453 result = emalloc(result_len + 1); 2454 2455 memcpy(result, Z_STRVAL_P(orig_str), f); 2456 memcpy((result + f), Z_STRVAL_P(repl_str), Z_STRLEN_P(repl_str)); 2457 memcpy((result + f + Z_STRLEN_P(repl_str)), Z_STRVAL_P(orig_str) + f + l, Z_STRLEN_P(orig_str) - f - l); 2458 if(Z_TYPE_PP(tmp_repl) != IS_STRING) { 2459 zval_dtor(repl_str); 2460 } 2461 } else { 2462 result = emalloc(result_len + 1); 2463 2464 memcpy(result, Z_STRVAL_P(orig_str), f); 2465 memcpy((result + f), Z_STRVAL_P(orig_str) + f + l, Z_STRLEN_P(orig_str) - f - l); 2466 } 2467 } else { 2468 result_len += Z_STRLEN_PP(repl); 2469 2470 result = emalloc(result_len + 1); 2471 2472 memcpy(result, Z_STRVAL_P(orig_str), f); 2473 memcpy((result + f), Z_STRVAL_PP(repl), Z_STRLEN_PP(repl)); 2474 memcpy((result + f + Z_STRLEN_PP(repl)), Z_STRVAL_P(orig_str) + f + l, Z_STRLEN_P(orig_str) - f - l); 2475 } 2476 2477 result[result_len] = '\0'; 2478 2479 if (zend_hash_get_current_key_ex(Z_ARRVAL_PP(str), &str_index, &str_index_len, &num_index, 0, &pos_str) == HASH_KEY_IS_STRING) { 2480 add_assoc_stringl_ex(return_value, str_index, str_index_len, result, result_len, 0); 2481 } else { 2482 add_index_stringl(return_value, num_index, result, result_len, 0); 2483 } 2484 2485 if(Z_TYPE_PP(tmp_str) != IS_STRING) { 2486 zval_dtor(orig_str); 2487 } 2488 zend_hash_move_forward_ex(Z_ARRVAL_PP(str), &pos_str); 2489 } /*while*/ 2490 } /* if */ 2491} 2492/* }}} */ 2493 2494/* {{{ proto string quotemeta(string str) 2495 Quotes meta characters */ 2496PHP_FUNCTION(quotemeta) 2497{ 2498 char *str, *old; 2499 char *old_end; 2500 char *p, *q; 2501 char c; 2502 int old_len; 2503 2504 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &old, &old_len) == FAILURE) { 2505 return; 2506 } 2507 2508 old_end = old + old_len; 2509 2510 if (old == old_end) { 2511 RETURN_FALSE; 2512 } 2513 2514 str = safe_emalloc(2, old_len, 1); 2515 2516 for (p = old, q = str; p != old_end; p++) { 2517 c = *p; 2518 switch (c) { 2519 case '.': 2520 case '\\': 2521 case '+': 2522 case '*': 2523 case '?': 2524 case '[': 2525 case '^': 2526 case ']': 2527 case '$': 2528 case '(': 2529 case ')': 2530 *q++ = '\\'; 2531 /* break is missing _intentionally_ */ 2532 default: 2533 *q++ = c; 2534 } 2535 } 2536 *q = 0; 2537 2538 RETURN_STRINGL(erealloc(str, q - str + 1), q - str, 0); 2539} 2540/* }}} */ 2541 2542/* {{{ proto int ord(string character) 2543 Returns ASCII value of character */ 2544PHP_FUNCTION(ord) 2545{ 2546 char *str; 2547 int str_len; 2548 2549 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) { 2550 return; 2551 } 2552 2553 RETURN_LONG((unsigned char) str[0]); 2554} 2555/* }}} */ 2556 2557/* {{{ proto string chr(int ascii) 2558 Converts ASCII code to a character */ 2559PHP_FUNCTION(chr) 2560{ 2561 long c; 2562 char temp[2]; 2563 2564 if (ZEND_NUM_ARGS() != 1) { 2565 WRONG_PARAM_COUNT; 2566 } 2567 2568 if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "l", &c) == FAILURE) { 2569 c = 0; 2570 } 2571 2572 temp[0] = (char)c; 2573 temp[1] = '\0'; 2574 2575 RETURN_STRINGL(temp, 1, 1); 2576} 2577/* }}} */ 2578 2579/* {{{ php_ucfirst 2580 Uppercase the first character of the word in a native string */ 2581static void php_ucfirst(char *str) 2582{ 2583 register char *r; 2584 r = str; 2585 *r = toupper((unsigned char) *r); 2586} 2587/* }}} */ 2588 2589/* {{{ proto string ucfirst(string str) 2590 Makes a string's first character uppercase */ 2591PHP_FUNCTION(ucfirst) 2592{ 2593 char *str; 2594 int str_len; 2595 2596 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) { 2597 return; 2598 } 2599 2600 if (!str_len) { 2601 RETURN_EMPTY_STRING(); 2602 } 2603 2604 ZVAL_STRINGL(return_value, str, str_len, 1); 2605 php_ucfirst(Z_STRVAL_P(return_value)); 2606} 2607/* }}} */ 2608 2609/* {{{ 2610 Lowercase the first character of the word in a native string */ 2611static void php_lcfirst(char *str) 2612{ 2613 register char *r; 2614 r = str; 2615 *r = tolower((unsigned char) *r); 2616} 2617/* }}} */ 2618 2619/* {{{ proto string lcfirst(string str) 2620 Make a string's first character lowercase */ 2621PHP_FUNCTION(lcfirst) 2622{ 2623 char *str; 2624 int str_len; 2625 2626 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) { 2627 return; 2628 } 2629 2630 if (!str_len) { 2631 RETURN_EMPTY_STRING(); 2632 } 2633 2634 ZVAL_STRINGL(return_value, str, str_len, 1); 2635 php_lcfirst(Z_STRVAL_P(return_value)); 2636} 2637/* }}} */ 2638 2639/* {{{ proto string ucwords(string str) 2640 Uppercase the first character of every word in a string */ 2641PHP_FUNCTION(ucwords) 2642{ 2643 char *str; 2644 register char *r, *r_end; 2645 int str_len; 2646 2647 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) { 2648 return; 2649 } 2650 2651 if (!str_len) { 2652 RETURN_EMPTY_STRING(); 2653 } 2654 2655 ZVAL_STRINGL(return_value, str, str_len, 1); 2656 r = Z_STRVAL_P(return_value); 2657 2658 *r = toupper((unsigned char) *r); 2659 for (r_end = r + Z_STRLEN_P(return_value) - 1; r < r_end; ) { 2660 if (isspace((int) *(unsigned char *)r++)) { 2661 *r = toupper((unsigned char) *r); 2662 } 2663 } 2664} 2665/* }}} */ 2666 2667/* {{{ php_strtr 2668 */ 2669PHPAPI char *php_strtr(char *str, int len, char *str_from, char *str_to, int trlen) 2670{ 2671 int i; 2672 unsigned char xlat[256]; 2673 2674 if ((trlen < 1) || (len < 1)) { 2675 return str; 2676 } 2677 2678 for (i = 0; i < 256; xlat[i] = i, i++); 2679 2680 for (i = 0; i < trlen; i++) { 2681 xlat[(unsigned char) str_from[i]] = str_to[i]; 2682 } 2683 2684 for (i = 0; i < len; i++) { 2685 str[i] = xlat[(unsigned char) str[i]]; 2686 } 2687 2688 return str; 2689} 2690/* }}} */ 2691 2692/* {{{ php_strtr_array 2693 */ 2694static void php_strtr_array(zval *return_value, char *str, int slen, HashTable *hash) 2695{ 2696 zval **entry; 2697 char *string_key; 2698 uint string_key_len; 2699 zval **trans; 2700 zval ctmp; 2701 ulong num_key; 2702 int minlen = 128*1024; 2703 int maxlen = 0, pos, len, found; 2704 char *key; 2705 HashPosition hpos; 2706 smart_str result = {0}; 2707 HashTable tmp_hash; 2708 2709 zend_hash_init(&tmp_hash, zend_hash_num_elements(hash), NULL, NULL, 0); 2710 zend_hash_internal_pointer_reset_ex(hash, &hpos); 2711 while (zend_hash_get_current_data_ex(hash, (void **)&entry, &hpos) == SUCCESS) { 2712 switch (zend_hash_get_current_key_ex(hash, &string_key, &string_key_len, &num_key, 0, &hpos)) { 2713 case HASH_KEY_IS_STRING: 2714 len = string_key_len-1; 2715 if (len < 1) { 2716 zend_hash_destroy(&tmp_hash); 2717 RETURN_FALSE; 2718 } 2719 zend_hash_add(&tmp_hash, string_key, string_key_len, entry, sizeof(zval*), NULL); 2720 if (len > maxlen) { 2721 maxlen = len; 2722 } 2723 if (len < minlen) { 2724 minlen = len; 2725 } 2726 break; 2727 2728 case HASH_KEY_IS_LONG: 2729 Z_TYPE(ctmp) = IS_LONG; 2730 Z_LVAL(ctmp) = num_key; 2731 2732 convert_to_string(&ctmp); 2733 len = Z_STRLEN(ctmp); 2734 zend_hash_add(&tmp_hash, Z_STRVAL(ctmp), len+1, entry, sizeof(zval*), NULL); 2735 zval_dtor(&ctmp); 2736 2737 if (len > maxlen) { 2738 maxlen = len; 2739 } 2740 if (len < minlen) { 2741 minlen = len; 2742 } 2743 break; 2744 } 2745 zend_hash_move_forward_ex(hash, &hpos); 2746 } 2747 2748 key = emalloc(maxlen+1); 2749 pos = 0; 2750 2751 while (pos < slen) { 2752 if ((pos + maxlen) > slen) { 2753 maxlen = slen - pos; 2754 } 2755 2756 found = 0; 2757 memcpy(key, str+pos, maxlen); 2758 2759 for (len = maxlen; len >= minlen; len--) { 2760 key[len] = 0; 2761 2762 if (zend_hash_find(&tmp_hash, key, len+1, (void**)&trans) == SUCCESS) { 2763 char *tval; 2764 int tlen; 2765 zval tmp; 2766 2767 if (Z_TYPE_PP(trans) != IS_STRING) { 2768 tmp = **trans; 2769 zval_copy_ctor(&tmp); 2770 convert_to_string(&tmp); 2771 tval = Z_STRVAL(tmp); 2772 tlen = Z_STRLEN(tmp); 2773 } else { 2774 tval = Z_STRVAL_PP(trans); 2775 tlen = Z_STRLEN_PP(trans); 2776 } 2777 2778 smart_str_appendl(&result, tval, tlen); 2779 pos += len; 2780 found = 1; 2781 2782 if (Z_TYPE_PP(trans) != IS_STRING) { 2783 zval_dtor(&tmp); 2784 } 2785 break; 2786 } 2787 } 2788 2789 if (! found) { 2790 smart_str_appendc(&result, str[pos++]); 2791 } 2792 } 2793 2794 efree(key); 2795 zend_hash_destroy(&tmp_hash); 2796 smart_str_0(&result); 2797 RETVAL_STRINGL(result.c, result.len, 0); 2798} 2799/* }}} */ 2800 2801/* {{{ proto string strtr(string str, string from[, string to]) 2802 Translates characters in str using given translation tables */ 2803PHP_FUNCTION(strtr) 2804{ 2805 zval **from; 2806 char *str, *to = NULL; 2807 int str_len, to_len = 0; 2808 int ac = ZEND_NUM_ARGS(); 2809 2810 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sZ|s", &str, &str_len, &from, &to, &to_len) == FAILURE) { 2811 return; 2812 } 2813 2814 if (ac == 2 && Z_TYPE_PP(from) != IS_ARRAY) { 2815 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The second argument is not an array"); 2816 RETURN_FALSE; 2817 } 2818 2819 /* shortcut for empty string */ 2820 if (str_len == 0) { 2821 RETURN_EMPTY_STRING(); 2822 } 2823 2824 if (ac == 2) { 2825 php_strtr_array(return_value, str, str_len, HASH_OF(*from)); 2826 } else { 2827 convert_to_string_ex(from); 2828 2829 ZVAL_STRINGL(return_value, str, str_len, 1); 2830 2831 php_strtr(Z_STRVAL_P(return_value), 2832 Z_STRLEN_P(return_value), 2833 Z_STRVAL_PP(from), 2834 to, 2835 MIN(Z_STRLEN_PP(from), 2836 to_len)); 2837 } 2838} 2839/* }}} */ 2840 2841/* {{{ proto string strrev(string str) 2842 Reverse a string */ 2843PHP_FUNCTION(strrev) 2844{ 2845 char *str; 2846 char *e, *n, *p; 2847 int str_len; 2848 2849 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) { 2850 return; 2851 } 2852 2853 n = emalloc(str_len+1); 2854 p = n; 2855 2856 e = str + str_len; 2857 2858 while (--e>=str) { 2859 *p++ = *e; 2860 } 2861 2862 *p = '\0'; 2863 2864 RETVAL_STRINGL(n, str_len, 0); 2865} 2866/* }}} */ 2867 2868/* {{{ php_similar_str 2869 */ 2870static void php_similar_str(const char *txt1, int len1, const char *txt2, int len2, int *pos1, int *pos2, int *max) 2871{ 2872 char *p, *q; 2873 char *end1 = (char *) txt1 + len1; 2874 char *end2 = (char *) txt2 + len2; 2875 int l; 2876 2877 *max = 0; 2878 for (p = (char *) txt1; p < end1; p++) { 2879 for (q = (char *) txt2; q < end2; q++) { 2880 for (l = 0; (p + l < end1) && (q + l < end2) && (p[l] == q[l]); l++); 2881 if (l > *max) { 2882 *max = l; 2883 *pos1 = p - txt1; 2884 *pos2 = q - txt2; 2885 } 2886 } 2887 } 2888} 2889/* }}} */ 2890 2891/* {{{ php_similar_char 2892 */ 2893static int php_similar_char(const char *txt1, int len1, const char *txt2, int len2) 2894{ 2895 int sum; 2896 int pos1, pos2, max; 2897 2898 php_similar_str(txt1, len1, txt2, len2, &pos1, &pos2, &max); 2899 if ((sum = max)) { 2900 if (pos1 && pos2) { 2901 sum += php_similar_char(txt1, pos1, 2902 txt2, pos2); 2903 } 2904 if ((pos1 + max < len1) && (pos2 + max < len2)) { 2905 sum += php_similar_char(txt1 + pos1 + max, len1 - pos1 - max, 2906 txt2 + pos2 + max, len2 - pos2 - max); 2907 } 2908 } 2909 2910 return sum; 2911} 2912/* }}} */ 2913 2914/* {{{ proto int similar_text(string str1, string str2 [, float percent]) 2915 Calculates the similarity between two strings */ 2916PHP_FUNCTION(similar_text) 2917{ 2918 char *t1, *t2; 2919 zval **percent = NULL; 2920 int ac = ZEND_NUM_ARGS(); 2921 int sim; 2922 int t1_len, t2_len; 2923 2924 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|Z", &t1, &t1_len, &t2, &t2_len, &percent) == FAILURE) { 2925 return; 2926 } 2927 2928 if (ac > 2) { 2929 convert_to_double_ex(percent); 2930 } 2931 2932 if (t1_len + t2_len == 0) { 2933 if (ac > 2) { 2934 Z_DVAL_PP(percent) = 0; 2935 } 2936 2937 RETURN_LONG(0); 2938 } 2939 2940 sim = php_similar_char(t1, t1_len, t2, t2_len); 2941 2942 if (ac > 2) { 2943 Z_DVAL_PP(percent) = sim * 200.0 / (t1_len + t2_len); 2944 } 2945 2946 RETURN_LONG(sim); 2947} 2948/* }}} */ 2949 2950/* {{{ php_stripslashes 2951 * 2952 * be careful, this edits the string in-place */ 2953PHPAPI void php_stripslashes(char *str, int *len TSRMLS_DC) 2954{ 2955 char *s, *t; 2956 int l; 2957 2958 if (len != NULL) { 2959 l = *len; 2960 } else { 2961 l = strlen(str); 2962 } 2963 s = str; 2964 t = str; 2965 2966 if (PG(magic_quotes_sybase)) { 2967 while (l > 0) { 2968 if (*t == '\'') { 2969 if ((l > 0) && (t[1] == '\'')) { 2970 t++; 2971 if (len != NULL) { 2972 (*len)--; 2973 } 2974 l--; 2975 } 2976 *s++ = *t++; 2977 } else if (*t == '\\' && t[1] == '0' && l > 0) { 2978 *s++='\0'; 2979 t+=2; 2980 if (len != NULL) { 2981 (*len)--; 2982 } 2983 l--; 2984 } else { 2985 *s++ = *t++; 2986 } 2987 l--; 2988 } 2989 *s = '\0'; 2990 2991 return; 2992 } 2993 2994 while (l > 0) { 2995 if (*t == '\\') { 2996 t++; /* skip the slash */ 2997 if (len != NULL) { 2998 (*len)--; 2999 } 3000 l--; 3001 if (l > 0) { 3002 if (*t == '0') { 3003 *s++='\0'; 3004 t++; 3005 } else { 3006 *s++ = *t++; /* preserve the next character */ 3007 } 3008 l--; 3009 } 3010 } else { 3011 *s++ = *t++; 3012 l--; 3013 } 3014 } 3015 if (s != t) { 3016 *s = '\0'; 3017 } 3018} 3019/* }}} */ 3020 3021/* {{{ proto string addcslashes(string str, string charlist) 3022 Escapes all chars mentioned in charlist with backslash. It creates octal representations if asked to backslash characters with 8th bit set or with ASCII<32 (except '\n', '\r', '\t' etc...) */ 3023PHP_FUNCTION(addcslashes) 3024{ 3025 char *str, *what; 3026 int str_len, what_len; 3027 3028 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &str, &str_len, &what, &what_len) == FAILURE) { 3029 return; 3030 } 3031 3032 if (str_len == 0) { 3033 RETURN_EMPTY_STRING(); 3034 } 3035 3036 if (what_len == 0) { 3037 RETURN_STRINGL(str, str_len, 1); 3038 } 3039 3040 Z_STRVAL_P(return_value) = php_addcslashes(str, str_len, &Z_STRLEN_P(return_value), 0, what, what_len TSRMLS_CC); 3041 RETURN_STRINGL(Z_STRVAL_P(return_value), Z_STRLEN_P(return_value), 0); 3042} 3043/* }}} */ 3044 3045/* {{{ proto string addslashes(string str) 3046 Escapes single quote, double quotes and backslash characters in a string with backslashes */ 3047PHP_FUNCTION(addslashes) 3048{ 3049 char *str; 3050 int str_len; 3051 3052 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) { 3053 return; 3054 } 3055 3056 if (str_len == 0) { 3057 RETURN_EMPTY_STRING(); 3058 } 3059 3060 RETURN_STRING(php_addslashes(str, 3061 str_len, 3062 &Z_STRLEN_P(return_value), 0 3063 TSRMLS_CC), 0); 3064} 3065/* }}} */ 3066 3067/* {{{ proto string stripcslashes(string str) 3068 Strips backslashes from a string. Uses C-style conventions */ 3069PHP_FUNCTION(stripcslashes) 3070{ 3071 char *str; 3072 int str_len; 3073 3074 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) { 3075 return; 3076 } 3077 3078 ZVAL_STRINGL(return_value, str, str_len, 1); 3079 php_stripcslashes(Z_STRVAL_P(return_value), &Z_STRLEN_P(return_value)); 3080} 3081/* }}} */ 3082 3083/* {{{ proto string stripslashes(string str) 3084 Strips backslashes from a string */ 3085PHP_FUNCTION(stripslashes) 3086{ 3087 char *str; 3088 int str_len; 3089 3090 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) { 3091 return; 3092 } 3093 3094 ZVAL_STRINGL(return_value, str, str_len, 1); 3095 php_stripslashes(Z_STRVAL_P(return_value), &Z_STRLEN_P(return_value) TSRMLS_CC); 3096} 3097/* }}} */ 3098 3099#ifndef HAVE_STRERROR 3100/* {{{ php_strerror 3101 */ 3102char *php_strerror(int errnum) 3103{ 3104 extern int sys_nerr; 3105 extern char *sys_errlist[]; 3106 TSRMLS_FETCH(); 3107 3108 if ((unsigned int) errnum < sys_nerr) { 3109 return(sys_errlist[errnum]); 3110 } 3111 3112 (void) snprintf(BG(str_ebuf), sizeof(php_basic_globals.str_ebuf), "Unknown error: %d", errnum); 3113 return(BG(str_ebuf)); 3114} 3115/* }}} */ 3116#endif 3117 3118/* {{{ php_stripcslashes 3119 */ 3120PHPAPI void php_stripcslashes(char *str, int *len) 3121{ 3122 char *source, *target, *end; 3123 int nlen = *len, i; 3124 char numtmp[4]; 3125 3126 for (source=str, end=str+nlen, target=str; source < end; source++) { 3127 if (*source == '\\' && source+1 < end) { 3128 source++; 3129 switch (*source) { 3130 case 'n': *target++='\n'; nlen--; break; 3131 case 'r': *target++='\r'; nlen--; break; 3132 case 'a': *target++='\a'; nlen--; break; 3133 case 't': *target++='\t'; nlen--; break; 3134 case 'v': *target++='\v'; nlen--; break; 3135 case 'b': *target++='\b'; nlen--; break; 3136 case 'f': *target++='\f'; nlen--; break; 3137 case '\\': *target++='\\'; nlen--; break; 3138 case 'x': 3139 if (source+1 < end && isxdigit((int)(*(source+1)))) { 3140 numtmp[0] = *++source; 3141 if (source+1 < end && isxdigit((int)(*(source+1)))) { 3142 numtmp[1] = *++source; 3143 numtmp[2] = '\0'; 3144 nlen-=3; 3145 } else { 3146 numtmp[1] = '\0'; 3147 nlen-=2; 3148 } 3149 *target++=(char)strtol(numtmp, NULL, 16); 3150 break; 3151 } 3152 /* break is left intentionally */ 3153 default: 3154 i=0; 3155 while (source < end && *source >= '0' && *source <= '7' && i<3) { 3156 numtmp[i++] = *source++; 3157 } 3158 if (i) { 3159 numtmp[i]='\0'; 3160 *target++=(char)strtol(numtmp, NULL, 8); 3161 nlen-=i; 3162 source--; 3163 } else { 3164 *target++=*source; 3165 nlen--; 3166 } 3167 } 3168 } else { 3169 *target++=*source; 3170 } 3171 } 3172 3173 if (nlen != 0) { 3174 *target='\0'; 3175 } 3176 3177 *len = nlen; 3178} 3179/* }}} */ 3180 3181/* {{{ php_addcslashes 3182 */ 3183PHPAPI char *php_addcslashes(char *str, int length, int *new_length, int should_free, char *what, int wlength TSRMLS_DC) 3184{ 3185 char flags[256]; 3186 char *new_str = safe_emalloc(4, (length?length:(length=strlen(str))), 1); 3187 char *source, *target; 3188 char *end; 3189 char c; 3190 int newlen; 3191 3192 if (!wlength) { 3193 wlength = strlen(what); 3194 } 3195 3196 php_charmask((unsigned char *)what, wlength, flags TSRMLS_CC); 3197 3198 for (source = str, end = source + length, target = new_str; source < end; source++) { 3199 c = *source; 3200 if (flags[(unsigned char)c]) { 3201 if ((unsigned char) c < 32 || (unsigned char) c > 126) { 3202 *target++ = '\\'; 3203 switch (c) { 3204 case '\n': *target++ = 'n'; break; 3205 case '\t': *target++ = 't'; break; 3206 case '\r': *target++ = 'r'; break; 3207 case '\a': *target++ = 'a'; break; 3208 case '\v': *target++ = 'v'; break; 3209 case '\b': *target++ = 'b'; break; 3210 case '\f': *target++ = 'f'; break; 3211 default: target += sprintf(target, "%03o", (unsigned char) c); 3212 } 3213 continue; 3214 } 3215 *target++ = '\\'; 3216 } 3217 *target++ = c; 3218 } 3219 *target = 0; 3220 newlen = target - new_str; 3221 if (target - new_str < length * 4) { 3222 new_str = erealloc(new_str, newlen + 1); 3223 } 3224 if (new_length) { 3225 *new_length = newlen; 3226 } 3227 if (should_free) { 3228 STR_FREE(str); 3229 } 3230 return new_str; 3231} 3232/* }}} */ 3233 3234/* {{{ php_addslashes 3235 */ 3236PHPAPI char *php_addslashes(char *str, int length, int *new_length, int should_free TSRMLS_DC) 3237{ 3238 return php_addslashes_ex(str, length, new_length, should_free, 0 TSRMLS_CC); 3239} 3240/* }}} */ 3241 3242/* {{{ php_addslashes_ex 3243 */ 3244PHPAPI char *php_addslashes_ex(char *str, int length, int *new_length, int should_free, int ignore_sybase TSRMLS_DC) 3245{ 3246 /* maximum string length, worst case situation */ 3247 char *new_str; 3248 char *source, *target; 3249 char *end; 3250 int local_new_length; 3251 3252 if (!new_length) { 3253 new_length = &local_new_length; 3254 } 3255 if (!str) { 3256 *new_length = 0; 3257 return str; 3258 } 3259 new_str = (char *) safe_emalloc(2, (length ? length : (length = strlen(str))), 1); 3260 source = str; 3261 end = source + length; 3262 target = new_str; 3263 3264 if (!ignore_sybase && PG(magic_quotes_sybase)) { 3265 while (source < end) { 3266 switch (*source) { 3267 case '\0': 3268 *target++ = '\\'; 3269 *target++ = '0'; 3270 break; 3271 case '\'': 3272 *target++ = '\''; 3273 *target++ = '\''; 3274 break; 3275 default: 3276 *target++ = *source; 3277 break; 3278 } 3279 source++; 3280 } 3281 } else { 3282 while (source < end) { 3283 switch (*source) { 3284 case '\0': 3285 *target++ = '\\'; 3286 *target++ = '0'; 3287 break; 3288 case '\'': 3289 case '\"': 3290 case '\\': 3291 *target++ = '\\'; 3292 /* break is missing *intentionally* */ 3293 default: 3294 *target++ = *source; 3295 break; 3296 } 3297 3298 source++; 3299 } 3300 } 3301 3302 *target = 0; 3303 *new_length = target - new_str; 3304 if (should_free) { 3305 STR_FREE(str); 3306 } 3307 new_str = (char *) erealloc(new_str, *new_length + 1); 3308 return new_str; 3309} 3310/* }}} */ 3311 3312#define _HEB_BLOCK_TYPE_ENG 1 3313#define _HEB_BLOCK_TYPE_HEB 2 3314#define isheb(c) (((((unsigned char) c) >= 224) && (((unsigned char) c) <= 250)) ? 1 : 0) 3315#define _isblank(c) (((((unsigned char) c) == ' ' || ((unsigned char) c) == '\t')) ? 1 : 0) 3316#define _isnewline(c) (((((unsigned char) c) == '\n' || ((unsigned char) c) == '\r')) ? 1 : 0) 3317 3318/* {{{ php_char_to_str_ex 3319 */ 3320PHPAPI int php_char_to_str_ex(char *str, uint len, char from, char *to, int to_len, zval *result, int case_sensitivity, int *replace_count) 3321{ 3322 int char_count = 0; 3323 int replaced = 0; 3324 char *source, *target, *tmp, *source_end=str+len, *tmp_end = NULL; 3325 3326 if (case_sensitivity) { 3327 char *p = str, *e = p + len; 3328 while ((p = memchr(p, from, (e - p)))) { 3329 char_count++; 3330 p++; 3331 } 3332 } else { 3333 for (source = str; source < source_end; source++) { 3334 if (tolower(*source) == tolower(from)) { 3335 char_count++; 3336 } 3337 } 3338 } 3339 3340 if (char_count == 0 && case_sensitivity) { 3341 ZVAL_STRINGL(result, str, len, 1); 3342 return 0; 3343 } 3344 3345 Z_STRLEN_P(result) = len + (char_count * (to_len - 1)); 3346 Z_STRVAL_P(result) = target = safe_emalloc(char_count, to_len, len + 1); 3347 Z_TYPE_P(result) = IS_STRING; 3348 3349 if (case_sensitivity) { 3350 char *p = str, *e = p + len, *s = str; 3351 while ((p = memchr(p, from, (e - p)))) { 3352 memcpy(target, s, (p - s)); 3353 target += p - s; 3354 memcpy(target, to, to_len); 3355 target += to_len; 3356 p++; 3357 s = p; 3358 if (replace_count) { 3359 *replace_count += 1; 3360 } 3361 } 3362 if (s < e) { 3363 memcpy(target, s, (e - s)); 3364 target += e - s; 3365 } 3366 } else { 3367 for (source = str; source < source_end; source++) { 3368 if (tolower(*source) == tolower(from)) { 3369 replaced = 1; 3370 if (replace_count) { 3371 *replace_count += 1; 3372 } 3373 for (tmp = to, tmp_end = tmp+to_len; tmp < tmp_end; tmp++) { 3374 *target = *tmp; 3375 target++; 3376 } 3377 } else { 3378 *target = *source; 3379 target++; 3380 } 3381 } 3382 } 3383 *target = 0; 3384 return replaced; 3385} 3386/* }}} */ 3387 3388/* {{{ php_char_to_str 3389 */ 3390PHPAPI int php_char_to_str(char *str, uint len, char from, char *to, int to_len, zval *result) 3391{ 3392 return php_char_to_str_ex(str, len, from, to, to_len, result, 1, NULL); 3393} 3394/* }}} */ 3395 3396/* {{{ php_str_to_str_ex 3397 */ 3398PHPAPI char *php_str_to_str_ex(char *haystack, int length, 3399 char *needle, int needle_len, char *str, int str_len, int *_new_length, int case_sensitivity, int *replace_count) 3400{ 3401 char *new_str; 3402 3403 if (needle_len < length) { 3404 char *end, *haystack_dup = NULL, *needle_dup = NULL; 3405 char *e, *s, *p, *r; 3406 3407 if (needle_len == str_len) { 3408 new_str = estrndup(haystack, length); 3409 *_new_length = length; 3410 3411 if (case_sensitivity) { 3412 end = new_str + length; 3413 for (p = new_str; (r = php_memnstr(p, needle, needle_len, end)); p = r + needle_len) { 3414 memcpy(r, str, str_len); 3415 if (replace_count) { 3416 (*replace_count)++; 3417 } 3418 } 3419 } else { 3420 haystack_dup = estrndup(haystack, length); 3421 needle_dup = estrndup(needle, needle_len); 3422 php_strtolower(haystack_dup, length); 3423 php_strtolower(needle_dup, needle_len); 3424 end = haystack_dup + length; 3425 for (p = haystack_dup; (r = php_memnstr(p, needle_dup, needle_len, end)); p = r + needle_len) { 3426 memcpy(new_str + (r - haystack_dup), str, str_len); 3427 if (replace_count) { 3428 (*replace_count)++; 3429 } 3430 } 3431 efree(haystack_dup); 3432 efree(needle_dup); 3433 } 3434 return new_str; 3435 } else { 3436 if (!case_sensitivity) { 3437 haystack_dup = estrndup(haystack, length); 3438 needle_dup = estrndup(needle, needle_len); 3439 php_strtolower(haystack_dup, length); 3440 php_strtolower(needle_dup, needle_len); 3441 } 3442 3443 if (str_len < needle_len) { 3444 new_str = emalloc(length + 1); 3445 } else { 3446 int count = 0; 3447 char *o, *n, *endp; 3448 3449 if (case_sensitivity) { 3450 o = haystack; 3451 n = needle; 3452 } else { 3453 o = haystack_dup; 3454 n = needle_dup; 3455 } 3456 endp = o + length; 3457 3458 while ((o = php_memnstr(o, n, needle_len, endp))) { 3459 o += needle_len; 3460 count++; 3461 } 3462 if (count == 0) { 3463 /* Needle doesn't occur, shortcircuit the actual replacement. */ 3464 if (haystack_dup) { 3465 efree(haystack_dup); 3466 } 3467 if (needle_dup) { 3468 efree(needle_dup); 3469 } 3470 new_str = estrndup(haystack, length); 3471 if (_new_length) { 3472 *_new_length = length; 3473 } 3474 return new_str; 3475 } else { 3476 new_str = safe_emalloc(count, str_len - needle_len, length + 1); 3477 } 3478 } 3479 3480 e = s = new_str; 3481 3482 if (case_sensitivity) { 3483 end = haystack + length; 3484 for (p = haystack; (r = php_memnstr(p, needle, needle_len, end)); p = r + needle_len) { 3485 memcpy(e, p, r - p); 3486 e += r - p; 3487 memcpy(e, str, str_len); 3488 e += str_len; 3489 if (replace_count) { 3490 (*replace_count)++; 3491 } 3492 } 3493 3494 if (p < end) { 3495 memcpy(e, p, end - p); 3496 e += end - p; 3497 } 3498 } else { 3499 end = haystack_dup + length; 3500 3501 for (p = haystack_dup; (r = php_memnstr(p, needle_dup, needle_len, end)); p = r + needle_len) { 3502 memcpy(e, haystack + (p - haystack_dup), r - p); 3503 e += r - p; 3504 memcpy(e, str, str_len); 3505 e += str_len; 3506 if (replace_count) { 3507 (*replace_count)++; 3508 } 3509 } 3510 3511 if (p < end) { 3512 memcpy(e, haystack + (p - haystack_dup), end - p); 3513 e += end - p; 3514 } 3515 } 3516 3517 if (haystack_dup) { 3518 efree(haystack_dup); 3519 } 3520 if (needle_dup) { 3521 efree(needle_dup); 3522 } 3523 3524 *e = '\0'; 3525 *_new_length = e - s; 3526 3527 new_str = erealloc(new_str, *_new_length + 1); 3528 return new_str; 3529 } 3530 } else if (needle_len > length) { 3531nothing_todo: 3532 *_new_length = length; 3533 new_str = estrndup(haystack, length); 3534 return new_str; 3535 } else { 3536 if (case_sensitivity && memcmp(haystack, needle, length)) { 3537 goto nothing_todo; 3538 } else if (!case_sensitivity) { 3539 char *l_haystack, *l_needle; 3540 3541 l_haystack = estrndup(haystack, length); 3542 l_needle = estrndup(needle, length); 3543 3544 php_strtolower(l_haystack, length); 3545 php_strtolower(l_needle, length); 3546 3547 if (memcmp(l_haystack, l_needle, length)) { 3548 efree(l_haystack); 3549 efree(l_needle); 3550 goto nothing_todo; 3551 } 3552 efree(l_haystack); 3553 efree(l_needle); 3554 } 3555 3556 *_new_length = str_len; 3557 new_str = estrndup(str, str_len); 3558 3559 if (replace_count) { 3560 (*replace_count)++; 3561 } 3562 return new_str; 3563 } 3564 3565} 3566/* }}} */ 3567 3568/* {{{ php_str_to_str 3569 */ 3570PHPAPI char *php_str_to_str(char *haystack, int length, 3571 char *needle, int needle_len, char *str, int str_len, int *_new_length) 3572{ 3573 return php_str_to_str_ex(haystack, length, needle, needle_len, str, str_len, _new_length, 1, NULL); 3574} 3575/* }}} */ 3576 3577/* {{{ php_str_replace_in_subject 3578 */ 3579static void php_str_replace_in_subject(zval *search, zval *replace, zval **subject, zval *result, int case_sensitivity, int *replace_count) 3580{ 3581 zval **search_entry, 3582 **replace_entry = NULL, 3583 temp_result; 3584 char *replace_value = NULL; 3585 int replace_len = 0; 3586 3587 /* Make sure we're dealing with strings. */ 3588 convert_to_string_ex(subject); 3589 Z_TYPE_P(result) = IS_STRING; 3590 if (Z_STRLEN_PP(subject) == 0) { 3591 ZVAL_STRINGL(result, "", 0, 1); 3592 return; 3593 } 3594 3595 /* If search is an array */ 3596 if (Z_TYPE_P(search) == IS_ARRAY) { 3597 /* Duplicate subject string for repeated replacement */ 3598 MAKE_COPY_ZVAL(subject, result); 3599 3600 zend_hash_internal_pointer_reset(Z_ARRVAL_P(search)); 3601 3602 if (Z_TYPE_P(replace) == IS_ARRAY) { 3603 zend_hash_internal_pointer_reset(Z_ARRVAL_P(replace)); 3604 } else { 3605 /* Set replacement value to the passed one */ 3606 replace_value = Z_STRVAL_P(replace); 3607 replace_len = Z_STRLEN_P(replace); 3608 } 3609 3610 /* For each entry in the search array, get the entry */ 3611 while (zend_hash_get_current_data(Z_ARRVAL_P(search), (void **) &search_entry) == SUCCESS) { 3612 /* Make sure we're dealing with strings. */ 3613 SEPARATE_ZVAL(search_entry); 3614 convert_to_string(*search_entry); 3615 if (Z_STRLEN_PP(search_entry) == 0) { 3616 zend_hash_move_forward(Z_ARRVAL_P(search)); 3617 if (Z_TYPE_P(replace) == IS_ARRAY) { 3618 zend_hash_move_forward(Z_ARRVAL_P(replace)); 3619 } 3620 continue; 3621 } 3622 3623 /* If replace is an array. */ 3624 if (Z_TYPE_P(replace) == IS_ARRAY) { 3625 /* Get current entry */ 3626 if (zend_hash_get_current_data(Z_ARRVAL_P(replace), (void **)&replace_entry) == SUCCESS) { 3627 /* Make sure we're dealing with strings. */ 3628 convert_to_string_ex(replace_entry); 3629 3630 /* Set replacement value to the one we got from array */ 3631 replace_value = Z_STRVAL_PP(replace_entry); 3632 replace_len = Z_STRLEN_PP(replace_entry); 3633 3634 zend_hash_move_forward(Z_ARRVAL_P(replace)); 3635 } else { 3636 /* We've run out of replacement strings, so use an empty one. */ 3637 replace_value = ""; 3638 replace_len = 0; 3639 } 3640 } 3641 3642 if (Z_STRLEN_PP(search_entry) == 1) { 3643 php_char_to_str_ex(Z_STRVAL_P(result), 3644 Z_STRLEN_P(result), 3645 Z_STRVAL_PP(search_entry)[0], 3646 replace_value, 3647 replace_len, 3648 &temp_result, 3649 case_sensitivity, 3650 replace_count); 3651 } else if (Z_STRLEN_PP(search_entry) > 1) { 3652 Z_STRVAL(temp_result) = php_str_to_str_ex(Z_STRVAL_P(result), Z_STRLEN_P(result), 3653 Z_STRVAL_PP(search_entry), Z_STRLEN_PP(search_entry), 3654 replace_value, replace_len, &Z_STRLEN(temp_result), case_sensitivity, replace_count); 3655 } 3656 3657 efree(Z_STRVAL_P(result)); 3658 Z_STRVAL_P(result) = Z_STRVAL(temp_result); 3659 Z_STRLEN_P(result) = Z_STRLEN(temp_result); 3660 3661 if (Z_STRLEN_P(result) == 0) { 3662 return; 3663 } 3664 3665 zend_hash_move_forward(Z_ARRVAL_P(search)); 3666 } 3667 } else { 3668 if (Z_STRLEN_P(search) == 1) { 3669 php_char_to_str_ex(Z_STRVAL_PP(subject), 3670 Z_STRLEN_PP(subject), 3671 Z_STRVAL_P(search)[0], 3672 Z_STRVAL_P(replace), 3673 Z_STRLEN_P(replace), 3674 result, 3675 case_sensitivity, 3676 replace_count); 3677 } else if (Z_STRLEN_P(search) > 1) { 3678 Z_STRVAL_P(result) = php_str_to_str_ex(Z_STRVAL_PP(subject), Z_STRLEN_PP(subject), 3679 Z_STRVAL_P(search), Z_STRLEN_P(search), 3680 Z_STRVAL_P(replace), Z_STRLEN_P(replace), &Z_STRLEN_P(result), case_sensitivity, replace_count); 3681 } else { 3682 MAKE_COPY_ZVAL(subject, result); 3683 } 3684 } 3685} 3686/* }}} */ 3687 3688/* {{{ php_str_replace_common 3689 */ 3690static void php_str_replace_common(INTERNAL_FUNCTION_PARAMETERS, int case_sensitivity) 3691{ 3692 zval **subject, **search, **replace, **subject_entry, **zcount = NULL; 3693 zval *result; 3694 char *string_key; 3695 uint string_key_len; 3696 ulong num_key; 3697 int count = 0; 3698 int argc = ZEND_NUM_ARGS(); 3699 3700 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZZ|Z", &search, &replace, &subject, &zcount) == FAILURE) { 3701 return; 3702 } 3703 3704 SEPARATE_ZVAL(search); 3705 SEPARATE_ZVAL(replace); 3706 SEPARATE_ZVAL(subject); 3707 3708 /* Make sure we're dealing with strings and do the replacement. */ 3709 if (Z_TYPE_PP(search) != IS_ARRAY) { 3710 convert_to_string_ex(search); 3711 convert_to_string_ex(replace); 3712 } else if (Z_TYPE_PP(replace) != IS_ARRAY) { 3713 convert_to_string_ex(replace); 3714 } 3715 3716 /* if subject is an array */ 3717 if (Z_TYPE_PP(subject) == IS_ARRAY) { 3718 array_init(return_value); 3719 zend_hash_internal_pointer_reset(Z_ARRVAL_PP(subject)); 3720 3721 /* For each subject entry, convert it to string, then perform replacement 3722 and add the result to the return_value array. */ 3723 while (zend_hash_get_current_data(Z_ARRVAL_PP(subject), (void **)&subject_entry) == SUCCESS) { 3724 if (Z_TYPE_PP(subject_entry) != IS_ARRAY && Z_TYPE_PP(subject_entry) != IS_OBJECT) { 3725 MAKE_STD_ZVAL(result); 3726 SEPARATE_ZVAL(subject_entry); 3727 php_str_replace_in_subject(*search, *replace, subject_entry, result, case_sensitivity, (argc > 3) ? &count : NULL); 3728 } else { 3729 ALLOC_ZVAL(result); 3730 Z_ADDREF_P(*subject_entry); 3731 COPY_PZVAL_TO_ZVAL(*result, *subject_entry); 3732 } 3733 /* Add to return array */ 3734 switch (zend_hash_get_current_key_ex(Z_ARRVAL_PP(subject), &string_key, 3735 &string_key_len, &num_key, 0, NULL)) { 3736 case HASH_KEY_IS_STRING: 3737 add_assoc_zval_ex(return_value, string_key, string_key_len, result); 3738 break; 3739 3740 case HASH_KEY_IS_LONG: 3741 add_index_zval(return_value, num_key, result); 3742 break; 3743 } 3744 3745 zend_hash_move_forward(Z_ARRVAL_PP(subject)); 3746 } 3747 } else { /* if subject is not an array */ 3748 php_str_replace_in_subject(*search, *replace, subject, return_value, case_sensitivity, (argc > 3) ? &count : NULL); 3749 } 3750 if (argc > 3) { 3751 zval_dtor(*zcount); 3752 ZVAL_LONG(*zcount, count); 3753 } 3754} 3755/* }}} */ 3756 3757/* {{{ proto mixed str_replace(mixed search, mixed replace, mixed subject [, int &replace_count]) 3758 Replaces all occurrences of search in haystack with replace */ 3759PHP_FUNCTION(str_replace) 3760{ 3761 php_str_replace_common(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); 3762} 3763/* }}} */ 3764 3765/* {{{ proto mixed str_ireplace(mixed search, mixed replace, mixed subject [, int &replace_count]) 3766 Replaces all occurrences of search in haystack with replace / case-insensitive */ 3767PHP_FUNCTION(str_ireplace) 3768{ 3769 php_str_replace_common(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); 3770} 3771/* }}} */ 3772 3773/* {{{ php_hebrev 3774 * 3775 * Converts Logical Hebrew text (Hebrew Windows style) to Visual text 3776 * Cheers/complaints/flames - Zeev Suraski <zeev@php.net> 3777 */ 3778static void php_hebrev(INTERNAL_FUNCTION_PARAMETERS, int convert_newlines) 3779{ 3780 char *str; 3781 char *heb_str, *tmp, *target, *broken_str; 3782 int block_start, block_end, block_type, block_length, i; 3783 long max_chars=0; 3784 int begin, end, char_count, orig_begin; 3785 int str_len; 3786 3787 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &str, &str_len, &max_chars) == FAILURE) { 3788 return; 3789 } 3790 3791 if (str_len == 0) { 3792 RETURN_FALSE; 3793 } 3794 3795 tmp = str; 3796 block_start=block_end=0; 3797 3798 heb_str = (char *) emalloc(str_len+1); 3799 target = heb_str+str_len; 3800 *target = 0; 3801 target--; 3802 3803 block_length=0; 3804 3805 if (isheb(*tmp)) { 3806 block_type = _HEB_BLOCK_TYPE_HEB; 3807 } else { 3808 block_type = _HEB_BLOCK_TYPE_ENG; 3809 } 3810 3811 do { 3812 if (block_type == _HEB_BLOCK_TYPE_HEB) { 3813 while ((isheb((int)*(tmp+1)) || _isblank((int)*(tmp+1)) || ispunct((int)*(tmp+1)) || (int)*(tmp+1)=='\n' ) && block_end<str_len-1) { 3814 tmp++; 3815 block_end++; 3816 block_length++; 3817 } 3818 for (i = block_start; i<= block_end; i++) { 3819 *target = str[i]; 3820 switch (*target) { 3821 case '(': 3822 *target = ')'; 3823 break; 3824 case ')': 3825 *target = '('; 3826 break; 3827 case '[': 3828 *target = ']'; 3829 break; 3830 case ']': 3831 *target = '['; 3832 break; 3833 case '{': 3834 *target = '}'; 3835 break; 3836 case '}': 3837 *target = '{'; 3838 break; 3839 case '<': 3840 *target = '>'; 3841 break; 3842 case '>': 3843 *target = '<'; 3844 break; 3845 case '\\': 3846 *target = '/'; 3847 break; 3848 case '/': 3849 *target = '\\'; 3850 break; 3851 default: 3852 break; 3853 } 3854 target--; 3855 } 3856 block_type = _HEB_BLOCK_TYPE_ENG; 3857 } else { 3858 while (!isheb(*(tmp+1)) && (int)*(tmp+1)!='\n' && block_end < str_len-1) { 3859 tmp++; 3860 block_end++; 3861 block_length++; 3862 } 3863 while ((_isblank((int)*tmp) || ispunct((int)*tmp)) && *tmp!='/' && *tmp!='-' && block_end > block_start) { 3864 tmp--; 3865 block_end--; 3866 } 3867 for (i = block_end; i >= block_start; i--) { 3868 *target = str[i]; 3869 target--; 3870 } 3871 block_type = _HEB_BLOCK_TYPE_HEB; 3872 } 3873 block_start=block_end+1; 3874 } while (block_end < str_len-1); 3875 3876 3877 broken_str = (char *) emalloc(str_len+1); 3878 begin=end=str_len-1; 3879 target = broken_str; 3880 3881 while (1) { 3882 char_count=0; 3883 while ((!max_chars || char_count < max_chars) && begin > 0) { 3884 char_count++; 3885 begin--; 3886 if (begin <= 0 || _isnewline(heb_str[begin])) { 3887 while (begin > 0 && _isnewline(heb_str[begin-1])) { 3888 begin--; 3889 char_count++; 3890 } 3891 break; 3892 } 3893 } 3894 if (char_count == max_chars) { /* try to avoid breaking words */ 3895 int new_char_count=char_count, new_begin=begin; 3896 3897 while (new_char_count > 0) { 3898 if (_isblank(heb_str[new_begin]) || _isnewline(heb_str[new_begin])) { 3899 break; 3900 } 3901 new_begin++; 3902 new_char_count--; 3903 } 3904 if (new_char_count > 0) { 3905 begin=new_begin; 3906 } 3907 } 3908 orig_begin=begin; 3909 3910 if (_isblank(heb_str[begin])) { 3911 heb_str[begin]='\n'; 3912 } 3913 while (begin <= end && _isnewline(heb_str[begin])) { /* skip leading newlines */ 3914 begin++; 3915 } 3916 for (i = begin; i <= end; i++) { /* copy content */ 3917 *target = heb_str[i]; 3918 target++; 3919 } 3920 for (i = orig_begin; i <= end && _isnewline(heb_str[i]); i++) { 3921 *target = heb_str[i]; 3922 target++; 3923 } 3924 begin=orig_begin; 3925 3926 if (begin <= 0) { 3927 *target = 0; 3928 break; 3929 } 3930 begin--; 3931 end=begin; 3932 } 3933 efree(heb_str); 3934 3935 if (convert_newlines) { 3936 php_char_to_str(broken_str, str_len,'\n', "<br />\n", 7, return_value); 3937 efree(broken_str); 3938 } else { 3939 Z_STRVAL_P(return_value) = broken_str; 3940 Z_STRLEN_P(return_value) = str_len; 3941 Z_TYPE_P(return_value) = IS_STRING; 3942 } 3943} 3944/* }}} */ 3945 3946/* {{{ proto string hebrev(string str [, int max_chars_per_line]) 3947 Converts logical Hebrew text to visual text */ 3948PHP_FUNCTION(hebrev) 3949{ 3950 php_hebrev(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); 3951} 3952/* }}} */ 3953 3954/* {{{ proto string hebrevc(string str [, int max_chars_per_line]) 3955 Converts logical Hebrew text to visual text with newline conversion */ 3956PHP_FUNCTION(hebrevc) 3957{ 3958 php_hebrev(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); 3959} 3960/* }}} */ 3961 3962/* {{{ proto string nl2br(string str [, bool is_xhtml]) 3963 Converts newlines to HTML line breaks */ 3964PHP_FUNCTION(nl2br) 3965{ 3966 /* in brief this inserts <br /> or <br> before matched regexp \n\r?|\r\n? */ 3967 char *tmp, *str; 3968 int new_length; 3969 char *end, *target; 3970 int repl_cnt = 0; 3971 int str_len; 3972 zend_bool is_xhtml = 1; 3973 3974 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &str, &str_len, &is_xhtml) == FAILURE) { 3975 return; 3976 } 3977 3978 tmp = str; 3979 end = str + str_len; 3980 3981 /* it is really faster to scan twice and allocate mem once instead of scanning once 3982 and constantly reallocing */ 3983 while (tmp < end) { 3984 if (*tmp == '\r') { 3985 if (*(tmp+1) == '\n') { 3986 tmp++; 3987 } 3988 repl_cnt++; 3989 } else if (*tmp == '\n') { 3990 if (*(tmp+1) == '\r') { 3991 tmp++; 3992 } 3993 repl_cnt++; 3994 } 3995 3996 tmp++; 3997 } 3998 3999 if (repl_cnt == 0) { 4000 RETURN_STRINGL(str, str_len, 1); 4001 } 4002 4003 { 4004 size_t repl_len = is_xhtml ? (sizeof("<br />") - 1) : (sizeof("<br>") - 1); 4005 4006 new_length = str_len + repl_cnt * repl_len; 4007 tmp = target = safe_emalloc(repl_cnt, repl_len, str_len + 1); 4008 } 4009 4010 while (str < end) { 4011 switch (*str) { 4012 case '\r': 4013 case '\n': 4014 *target++ = '<'; 4015 *target++ = 'b'; 4016 *target++ = 'r'; 4017 4018 if (is_xhtml) { 4019 *target++ = ' '; 4020 *target++ = '/'; 4021 } 4022 4023 *target++ = '>'; 4024 4025 if ((*str == '\r' && *(str+1) == '\n') || (*str == '\n' && *(str+1) == '\r')) { 4026 *target++ = *str++; 4027 } 4028 /* lack of a break; is intentional */ 4029 default: 4030 *target++ = *str; 4031 } 4032 4033 str++; 4034 } 4035 4036 *target = '\0'; 4037 4038 RETURN_STRINGL(tmp, new_length, 0); 4039} 4040/* }}} */ 4041 4042/* {{{ proto string strip_tags(string str [, string allowable_tags]) 4043 Strips HTML and PHP tags from a string */ 4044PHP_FUNCTION(strip_tags) 4045{ 4046 char *buf; 4047 char *str; 4048 zval **allow=NULL; 4049 char *allowed_tags=NULL; 4050 int allowed_tags_len=0; 4051 int str_len; 4052 size_t retval_len; 4053 4054 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|Z", &str, &str_len, &allow) == FAILURE) { 4055 return; 4056 } 4057 4058 /* To maintain a certain BC, we allow anything for the second parameter and return original string */ 4059 if (allow != NULL) { 4060 convert_to_string_ex(allow); 4061 allowed_tags = Z_STRVAL_PP(allow); 4062 allowed_tags_len = Z_STRLEN_PP(allow); 4063 } 4064 4065 buf = estrndup(str, str_len); 4066 retval_len = php_strip_tags_ex(buf, str_len, NULL, allowed_tags, allowed_tags_len, 0); 4067 RETURN_STRINGL(buf, retval_len, 0); 4068} 4069/* }}} */ 4070 4071/* {{{ proto string setlocale(mixed category, string locale [, string ...]) 4072 Set locale information */ 4073PHP_FUNCTION(setlocale) 4074{ 4075 zval ***args = NULL; 4076 zval **pcategory, **plocale; 4077 int num_args, cat, i = 0; 4078 char *loc, *retval; 4079 4080 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z+", &pcategory, &args, &num_args) == FAILURE) { 4081 return; 4082 } 4083 4084#ifdef HAVE_SETLOCALE 4085 if (Z_TYPE_PP(pcategory) == IS_LONG) { 4086 convert_to_long_ex(pcategory); 4087 cat = Z_LVAL_PP(pcategory); 4088 } else { 4089 /* FIXME: The following behaviour should be removed. */ 4090 char *category; 4091 4092 php_error_docref(NULL TSRMLS_CC, E_DEPRECATED, "Passing locale category name as string is deprecated. Use the LC_* -constants instead"); 4093 4094 convert_to_string_ex(pcategory); 4095 category = Z_STRVAL_PP(pcategory); 4096 4097 if (!strcasecmp("LC_ALL", category)) { 4098 cat = LC_ALL; 4099 } else if (!strcasecmp("LC_COLLATE", category)) { 4100 cat = LC_COLLATE; 4101 } else if (!strcasecmp("LC_CTYPE", category)) { 4102 cat = LC_CTYPE; 4103#ifdef LC_MESSAGES 4104 } else if (!strcasecmp("LC_MESSAGES", category)) { 4105 cat = LC_MESSAGES; 4106#endif 4107 } else if (!strcasecmp("LC_MONETARY", category)) { 4108 cat = LC_MONETARY; 4109 } else if (!strcasecmp("LC_NUMERIC", category)) { 4110 cat = LC_NUMERIC; 4111 } else if (!strcasecmp("LC_TIME", category)) { 4112 cat = LC_TIME; 4113 } else { 4114 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid locale category name %s, must be one of LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, or LC_TIME", category); 4115 4116 if (args) { 4117 efree(args); 4118 } 4119 RETURN_FALSE; 4120 } 4121 } 4122 4123 if (Z_TYPE_PP(args[0]) == IS_ARRAY) { 4124 zend_hash_internal_pointer_reset(Z_ARRVAL_PP(args[0])); 4125 } 4126 4127 while (1) { 4128 if (Z_TYPE_PP(args[0]) == IS_ARRAY) { 4129 if (!zend_hash_num_elements(Z_ARRVAL_PP(args[0]))) { 4130 break; 4131 } 4132 zend_hash_get_current_data(Z_ARRVAL_PP(args[0]), (void **)&plocale); 4133 } else { 4134 plocale = args[i]; 4135 } 4136 4137 convert_to_string_ex(plocale); 4138 4139 if (!strcmp ("0", Z_STRVAL_PP(plocale))) { 4140 loc = NULL; 4141 } else { 4142 loc = Z_STRVAL_PP(plocale); 4143 if (Z_STRLEN_PP(plocale) >= 255) { 4144 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Specified locale name is too long"); 4145 break; 4146 } 4147 } 4148 4149 retval = php_my_setlocale(cat, loc); 4150 zend_update_current_locale(); 4151 if (retval) { 4152 /* Remember if locale was changed */ 4153 if (loc) { 4154 STR_FREE(BG(locale_string)); 4155 BG(locale_string) = estrdup(retval); 4156 } 4157 4158 if (args) { 4159 efree(args); 4160 } 4161 RETURN_STRING(retval, 1); 4162 } 4163 4164 if (Z_TYPE_PP(args[0]) == IS_ARRAY) { 4165 if (zend_hash_move_forward(Z_ARRVAL_PP(args[0])) == FAILURE) break; 4166 } else { 4167 if (++i >= num_args) break; 4168 } 4169 } 4170 4171#endif 4172 if (args) { 4173 efree(args); 4174 } 4175 RETURN_FALSE; 4176} 4177/* }}} */ 4178 4179/* {{{ proto void parse_str(string encoded_string [, array result]) 4180 Parses GET/POST/COOKIE data and sets global variables */ 4181PHP_FUNCTION(parse_str) 4182{ 4183 char *arg; 4184 zval *arrayArg = NULL; 4185 char *res = NULL; 4186 int arglen; 4187 4188 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z", &arg, &arglen, &arrayArg) == FAILURE) { 4189 return; 4190 } 4191 4192 res = estrndup(arg, arglen); 4193 4194 if (arrayArg == NULL) { 4195 zval tmp; 4196 4197 if (!EG(active_symbol_table)) { 4198 zend_rebuild_symbol_table(TSRMLS_C); 4199 } 4200 Z_ARRVAL(tmp) = EG(active_symbol_table); 4201 sapi_module.treat_data(PARSE_STRING, res, &tmp TSRMLS_CC); 4202 } else { 4203 zval ret; 4204 4205 array_init(&ret); 4206 sapi_module.treat_data(PARSE_STRING, res, &ret TSRMLS_CC); 4207 /* Clear out the array that was passed in. */ 4208 zval_dtor(arrayArg); 4209 arrayArg->type = ret.type; 4210 arrayArg->value = ret.value; 4211 } 4212} 4213/* }}} */ 4214 4215#define PHP_TAG_BUF_SIZE 1023 4216 4217/* {{{ php_tag_find 4218 * 4219 * Check if tag is in a set of tags 4220 * 4221 * states: 4222 * 4223 * 0 start tag 4224 * 1 first non-whitespace char seen 4225 */ 4226int php_tag_find(char *tag, int len, char *set) { 4227 char c, *n, *t; 4228 int state=0, done=0; 4229 char *norm; 4230 4231 if (len <= 0) { 4232 return 0; 4233 } 4234 4235 norm = emalloc(len+1); 4236 4237 n = norm; 4238 t = tag; 4239 c = tolower(*t); 4240 /* 4241 normalize the tag removing leading and trailing whitespace 4242 and turn any <a whatever...> into just <a> and any </tag> 4243 into <tag> 4244 */ 4245 while (!done) { 4246 switch (c) { 4247 case '<': 4248 *(n++) = c; 4249 break; 4250 case '>': 4251 done =1; 4252 break; 4253 default: 4254 if (!isspace((int)c)) { 4255 if (state == 0) { 4256 state=1; 4257 } 4258 if (c != '/') { 4259 *(n++) = c; 4260 } 4261 } else { 4262 if (state == 1) 4263 done=1; 4264 } 4265 break; 4266 } 4267 c = tolower(*(++t)); 4268 } 4269 *(n++) = '>'; 4270 *n = '\0'; 4271 if (strstr(set, norm)) { 4272 done=1; 4273 } else { 4274 done=0; 4275 } 4276 efree(norm); 4277 return done; 4278} 4279/* }}} */ 4280 4281PHPAPI size_t php_strip_tags(char *rbuf, int len, int *stateptr, char *allow, int allow_len) /* {{{ */ 4282{ 4283 return php_strip_tags_ex(rbuf, len, stateptr, allow, allow_len, 0); 4284} 4285/* }}} */ 4286 4287/* {{{ php_strip_tags 4288 4289 A simple little state-machine to strip out html and php tags 4290 4291 State 0 is the output state, State 1 means we are inside a 4292 normal html tag and state 2 means we are inside a php tag. 4293 4294 The state variable is passed in to allow a function like fgetss 4295 to maintain state across calls to the function. 4296 4297 lc holds the last significant character read and br is a bracket 4298 counter. 4299 4300 When an allow string is passed in we keep track of the string 4301 in state 1 and when the tag is closed check it against the 4302 allow string to see if we should allow it. 4303 4304 swm: Added ability to strip <?xml tags without assuming it PHP 4305 code. 4306*/ 4307PHPAPI size_t php_strip_tags_ex(char *rbuf, int len, int *stateptr, char *allow, int allow_len, zend_bool allow_tag_spaces) 4308{ 4309 char *tbuf, *buf, *p, *tp, *rp, c, lc; 4310 int br, i=0, depth=0, in_q = 0; 4311 int state = 0, pos; 4312 4313 if (stateptr) 4314 state = *stateptr; 4315 4316 buf = estrndup(rbuf, len); 4317 c = *buf; 4318 lc = '\0'; 4319 p = buf; 4320 rp = rbuf; 4321 br = 0; 4322 if (allow) { 4323 php_strtolower(allow, allow_len); 4324 tbuf = emalloc(PHP_TAG_BUF_SIZE + 1); 4325 tp = tbuf; 4326 } else { 4327 tbuf = tp = NULL; 4328 } 4329 4330 while (i < len) { 4331 switch (c) { 4332 case '\0': 4333 break; 4334 case '<': 4335 if (in_q) { 4336 break; 4337 } 4338 if (isspace(*(p + 1)) && !allow_tag_spaces) { 4339 goto reg_char; 4340 } 4341 if (state == 0) { 4342 lc = '<'; 4343 state = 1; 4344 if (allow) { 4345 if (tp - tbuf >= PHP_TAG_BUF_SIZE) { 4346 pos = tp - tbuf; 4347 tbuf = erealloc(tbuf, (tp - tbuf) + PHP_TAG_BUF_SIZE + 1); 4348 tp = tbuf + pos; 4349 } 4350 *(tp++) = '<'; 4351 } 4352 } else if (state == 1) { 4353 depth++; 4354 } 4355 break; 4356 4357 case '(': 4358 if (state == 2) { 4359 if (lc != '"' && lc != '\'') { 4360 lc = '('; 4361 br++; 4362 } 4363 } else if (allow && state == 1) { 4364 if (tp - tbuf >= PHP_TAG_BUF_SIZE) { 4365 pos = tp - tbuf; 4366 tbuf = erealloc(tbuf, (tp - tbuf) + PHP_TAG_BUF_SIZE + 1); 4367 tp = tbuf + pos; 4368 } 4369 *(tp++) = c; 4370 } else if (state == 0) { 4371 *(rp++) = c; 4372 } 4373 break; 4374 4375 case ')': 4376 if (state == 2) { 4377 if (lc != '"' && lc != '\'') { 4378 lc = ')'; 4379 br--; 4380 } 4381 } else if (allow && state == 1) { 4382 if (tp - tbuf >= PHP_TAG_BUF_SIZE) { 4383 pos = tp - tbuf; 4384 tbuf = erealloc(tbuf, (tp - tbuf) + PHP_TAG_BUF_SIZE + 1); 4385 tp = tbuf + pos; 4386 } 4387 *(tp++) = c; 4388 } else if (state == 0) { 4389 *(rp++) = c; 4390 } 4391 break; 4392 4393 case '>': 4394 if (depth) { 4395 depth--; 4396 break; 4397 } 4398 4399 if (in_q) { 4400 break; 4401 } 4402 4403 switch (state) { 4404 case 1: /* HTML/XML */ 4405 lc = '>'; 4406 in_q = state = 0; 4407 if (allow) { 4408 if (tp - tbuf >= PHP_TAG_BUF_SIZE) { 4409 pos = tp - tbuf; 4410 tbuf = erealloc(tbuf, (tp - tbuf) + PHP_TAG_BUF_SIZE + 1); 4411 tp = tbuf + pos; 4412 } 4413 *(tp++) = '>'; 4414 *tp='\0'; 4415 if (php_tag_find(tbuf, tp-tbuf, allow)) { 4416 memcpy(rp, tbuf, tp-tbuf); 4417 rp += tp-tbuf; 4418 } 4419 tp = tbuf; 4420 } 4421 break; 4422 4423 case 2: /* PHP */ 4424 if (!br && lc != '\"' && *(p-1) == '?') { 4425 in_q = state = 0; 4426 tp = tbuf; 4427 } 4428 break; 4429 4430 case 3: 4431 in_q = state = 0; 4432 tp = tbuf; 4433 break; 4434 4435 case 4: /* JavaScript/CSS/etc... */ 4436 if (p >= buf + 2 && *(p-1) == '-' && *(p-2) == '-') { 4437 in_q = state = 0; 4438 tp = tbuf; 4439 } 4440 break; 4441 4442 default: 4443 *(rp++) = c; 4444 break; 4445 } 4446 break; 4447 4448 case '"': 4449 case '\'': 4450 if (state == 4) { 4451 /* Inside <!-- comment --> */ 4452 break; 4453 } else if (state == 2 && *(p-1) != '\\') { 4454 if (lc == c) { 4455 lc = '\0'; 4456 } else if (lc != '\\') { 4457 lc = c; 4458 } 4459 } else if (state == 0) { 4460 *(rp++) = c; 4461 } else if (allow && state == 1) { 4462 if (tp - tbuf >= PHP_TAG_BUF_SIZE) { 4463 pos = tp - tbuf; 4464 tbuf = erealloc(tbuf, (tp - tbuf) + PHP_TAG_BUF_SIZE + 1); 4465 tp = tbuf + pos; 4466 } 4467 *(tp++) = c; 4468 } 4469 if (state && p != buf && (state == 1 || *(p-1) != '\\') && (!in_q || *p == in_q)) { 4470 if (in_q) { 4471 in_q = 0; 4472 } else { 4473 in_q = *p; 4474 } 4475 } 4476 break; 4477 4478 case '!': 4479 /* JavaScript & Other HTML scripting languages */ 4480 if (state == 1 && *(p-1) == '<') { 4481 state = 3; 4482 lc = c; 4483 } else { 4484 if (state == 0) { 4485 *(rp++) = c; 4486 } else if (allow && state == 1) { 4487 if (tp - tbuf >= PHP_TAG_BUF_SIZE) { 4488 pos = tp - tbuf; 4489 tbuf = erealloc(tbuf, (tp - tbuf) + PHP_TAG_BUF_SIZE + 1); 4490 tp = tbuf + pos; 4491 } 4492 *(tp++) = c; 4493 } 4494 } 4495 break; 4496 4497 case '-': 4498 if (state == 3 && p >= buf + 2 && *(p-1) == '-' && *(p-2) == '!') { 4499 state = 4; 4500 } else { 4501 goto reg_char; 4502 } 4503 break; 4504 4505 case '?': 4506 4507 if (state == 1 && *(p-1) == '<') { 4508 br=0; 4509 state=2; 4510 break; 4511 } 4512 4513 case 'E': 4514 case 'e': 4515 /* !DOCTYPE exception */ 4516 if (state==3 && p > buf+6 4517 && tolower(*(p-1)) == 'p' 4518 && tolower(*(p-2)) == 'y' 4519 && tolower(*(p-3)) == 't' 4520 && tolower(*(p-4)) == 'c' 4521 && tolower(*(p-5)) == 'o' 4522 && tolower(*(p-6)) == 'd') { 4523 state = 1; 4524 break; 4525 } 4526 /* fall-through */ 4527 4528 case 'l': 4529 case 'L': 4530 4531 /* swm: If we encounter '<?xml' then we shouldn't be in 4532 * state == 2 (PHP). Switch back to HTML. 4533 */ 4534 4535 if (state == 2 && p > buf+2 && strncasecmp(p-2, "xm", 2) == 0) { 4536 state = 1; 4537 break; 4538 } 4539 4540 /* fall-through */ 4541 default: 4542reg_char: 4543 if (state == 0) { 4544 *(rp++) = c; 4545 } else if (allow && state == 1) { 4546 if (tp - tbuf >= PHP_TAG_BUF_SIZE) { 4547 pos = tp - tbuf; 4548 tbuf = erealloc(tbuf, (tp - tbuf) + PHP_TAG_BUF_SIZE + 1); 4549 tp = tbuf + pos; 4550 } 4551 *(tp++) = c; 4552 } 4553 break; 4554 } 4555 c = *(++p); 4556 i++; 4557 } 4558 if (rp < rbuf + len) { 4559 *rp = '\0'; 4560 } 4561 efree(buf); 4562 if (allow) 4563 efree(tbuf); 4564 if (stateptr) 4565 *stateptr = state; 4566 4567 return (size_t)(rp - rbuf); 4568} 4569/* }}} */ 4570 4571/* {{{ proto array str_getcsv(string input[, string delimiter[, string enclosure[, string escape]]]) 4572Parse a CSV string into an array */ 4573PHP_FUNCTION(str_getcsv) 4574{ 4575 char *str, delim = ',', enc = '"', esc = '\\'; 4576 char *delim_str = NULL, *enc_str = NULL, *esc_str = NULL; 4577 int str_len = 0, delim_len = 0, enc_len = 0, esc_len = 0; 4578 4579 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|sss", &str, &str_len, &delim_str, &delim_len, 4580 &enc_str, &enc_len, &esc_str, &esc_len) == FAILURE) { 4581 return; 4582 } 4583 4584 delim = delim_len ? delim_str[0] : delim; 4585 enc = enc_len ? enc_str[0] : enc; 4586 esc = esc_len ? esc_str[0] : esc; 4587 4588 php_fgetcsv(NULL, delim, enc, esc, str_len, str, return_value TSRMLS_CC); 4589} 4590/* }}} */ 4591 4592/* {{{ proto string str_repeat(string input, int mult) 4593 Returns the input string repeat mult times */ 4594PHP_FUNCTION(str_repeat) 4595{ 4596 char *input_str; /* Input string */ 4597 int input_len; 4598 long mult; /* Multiplier */ 4599 char *result; /* Resulting string */ 4600 size_t result_len; /* Length of the resulting string */ 4601 4602 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &input_str, &input_len, &mult) == FAILURE) { 4603 return; 4604 } 4605 4606 if (mult < 0) { 4607 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Second argument has to be greater than or equal to 0"); 4608 return; 4609 } 4610 4611 /* Don't waste our time if it's empty */ 4612 /* ... or if the multiplier is zero */ 4613 if (input_len == 0 || mult == 0) 4614 RETURN_EMPTY_STRING(); 4615 4616 /* Initialize the result string */ 4617 result_len = input_len * mult; 4618 result = (char *)safe_emalloc(input_len, mult, 1); 4619 4620 /* Heavy optimization for situations where input string is 1 byte long */ 4621 if (input_len == 1) { 4622 memset(result, *(input_str), mult); 4623 } else { 4624 char *s, *e, *ee; 4625 int l=0; 4626 memcpy(result, input_str, input_len); 4627 s = result; 4628 e = result + input_len; 4629 ee = result + result_len; 4630 4631 while (e<ee) { 4632 l = (e-s) < (ee-e) ? (e-s) : (ee-e); 4633 memmove(e, s, l); 4634 e += l; 4635 } 4636 } 4637 4638 result[result_len] = '\0'; 4639 4640 RETURN_STRINGL(result, result_len, 0); 4641} 4642/* }}} */ 4643 4644/* {{{ proto mixed count_chars(string input [, int mode]) 4645 Returns info about what characters are used in input */ 4646PHP_FUNCTION(count_chars) 4647{ 4648 char *input; 4649 int chars[256]; 4650 long mymode=0; 4651 unsigned char *buf; 4652 int len, inx; 4653 char retstr[256]; 4654 int retlen=0; 4655 4656 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &input, &len, &mymode) == FAILURE) { 4657 return; 4658 } 4659 4660 if (mymode < 0 || mymode > 4) { 4661 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown mode"); 4662 RETURN_FALSE; 4663 } 4664 4665 buf = (unsigned char *) input; 4666 memset((void*) chars, 0, sizeof(chars)); 4667 4668 while (len > 0) { 4669 chars[*buf]++; 4670 buf++; 4671 len--; 4672 } 4673 4674 if (mymode < 3) { 4675 array_init(return_value); 4676 } 4677 4678 for (inx = 0; inx < 256; inx++) { 4679 switch (mymode) { 4680 case 0: 4681 add_index_long(return_value, inx, chars[inx]); 4682 break; 4683 case 1: 4684 if (chars[inx] != 0) { 4685 add_index_long(return_value, inx, chars[inx]); 4686 } 4687 break; 4688 case 2: 4689 if (chars[inx] == 0) { 4690 add_index_long(return_value, inx, chars[inx]); 4691 } 4692 break; 4693 case 3: 4694 if (chars[inx] != 0) { 4695 retstr[retlen++] = inx; 4696 } 4697 break; 4698 case 4: 4699 if (chars[inx] == 0) { 4700 retstr[retlen++] = inx; 4701 } 4702 break; 4703 } 4704 } 4705 4706 if (mymode >= 3 && mymode <= 4) { 4707 RETURN_STRINGL(retstr, retlen, 1); 4708 } 4709} 4710/* }}} */ 4711 4712/* {{{ php_strnatcmp 4713 */ 4714static void php_strnatcmp(INTERNAL_FUNCTION_PARAMETERS, int fold_case) 4715{ 4716 char *s1, *s2; 4717 int s1_len, s2_len; 4718 4719 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &s1, &s1_len, &s2, &s2_len) == FAILURE) { 4720 return; 4721 } 4722 4723 RETURN_LONG(strnatcmp_ex(s1, s1_len, 4724 s2, s2_len, 4725 fold_case)); 4726} 4727/* }}} */ 4728 4729/* {{{ proto int strnatcmp(string s1, string s2) 4730 Returns the result of string comparison using 'natural' algorithm */ 4731PHP_FUNCTION(strnatcmp) 4732{ 4733 php_strnatcmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); 4734} 4735/* }}} */ 4736 4737/* {{{ proto array localeconv(void) 4738 Returns numeric formatting information based on the current locale */ 4739PHP_FUNCTION(localeconv) 4740{ 4741 zval *grouping, *mon_grouping; 4742 int len, i; 4743 4744 /* We don't need no stinkin' parameters... */ 4745 if (zend_parse_parameters_none() == FAILURE) { 4746 return; 4747 } 4748 4749 MAKE_STD_ZVAL(grouping); 4750 MAKE_STD_ZVAL(mon_grouping); 4751 4752 array_init(return_value); 4753 array_init(grouping); 4754 array_init(mon_grouping); 4755 4756#ifdef HAVE_LOCALECONV 4757 { 4758 struct lconv currlocdata; 4759 4760 localeconv_r( &currlocdata ); 4761 4762 /* Grab the grouping data out of the array */ 4763 len = strlen(currlocdata.grouping); 4764 4765 for (i = 0; i < len; i++) { 4766 add_index_long(grouping, i, currlocdata.grouping[i]); 4767 } 4768 4769 /* Grab the monetary grouping data out of the array */ 4770 len = strlen(currlocdata.mon_grouping); 4771 4772 for (i = 0; i < len; i++) { 4773 add_index_long(mon_grouping, i, currlocdata.mon_grouping[i]); 4774 } 4775 4776 add_assoc_string(return_value, "decimal_point", currlocdata.decimal_point, 1); 4777 add_assoc_string(return_value, "thousands_sep", currlocdata.thousands_sep, 1); 4778 add_assoc_string(return_value, "int_curr_symbol", currlocdata.int_curr_symbol, 1); 4779 add_assoc_string(return_value, "currency_symbol", currlocdata.currency_symbol, 1); 4780 add_assoc_string(return_value, "mon_decimal_point", currlocdata.mon_decimal_point, 1); 4781 add_assoc_string(return_value, "mon_thousands_sep", currlocdata.mon_thousands_sep, 1); 4782 add_assoc_string(return_value, "positive_sign", currlocdata.positive_sign, 1); 4783 add_assoc_string(return_value, "negative_sign", currlocdata.negative_sign, 1); 4784 add_assoc_long( return_value, "int_frac_digits", currlocdata.int_frac_digits ); 4785 add_assoc_long( return_value, "frac_digits", currlocdata.frac_digits ); 4786 add_assoc_long( return_value, "p_cs_precedes", currlocdata.p_cs_precedes ); 4787 add_assoc_long( return_value, "p_sep_by_space", currlocdata.p_sep_by_space ); 4788 add_assoc_long( return_value, "n_cs_precedes", currlocdata.n_cs_precedes ); 4789 add_assoc_long( return_value, "n_sep_by_space", currlocdata.n_sep_by_space ); 4790 add_assoc_long( return_value, "p_sign_posn", currlocdata.p_sign_posn ); 4791 add_assoc_long( return_value, "n_sign_posn", currlocdata.n_sign_posn ); 4792 } 4793#else 4794 /* Ok, it doesn't look like we have locale info floating around, so I guess it 4795 wouldn't hurt to just go ahead and return the POSIX locale information? */ 4796 4797 add_index_long(grouping, 0, -1); 4798 add_index_long(mon_grouping, 0, -1); 4799 4800 add_assoc_string(return_value, "decimal_point", "\x2E", 1); 4801 add_assoc_string(return_value, "thousands_sep", "", 1); 4802 add_assoc_string(return_value, "int_curr_symbol", "", 1); 4803 add_assoc_string(return_value, "currency_symbol", "", 1); 4804 add_assoc_string(return_value, "mon_decimal_point", "\x2E", 1); 4805 add_assoc_string(return_value, "mon_thousands_sep", "", 1); 4806 add_assoc_string(return_value, "positive_sign", "", 1); 4807 add_assoc_string(return_value, "negative_sign", "", 1); 4808 add_assoc_long( return_value, "int_frac_digits", CHAR_MAX ); 4809 add_assoc_long( return_value, "frac_digits", CHAR_MAX ); 4810 add_assoc_long( return_value, "p_cs_precedes", CHAR_MAX ); 4811 add_assoc_long( return_value, "p_sep_by_space", CHAR_MAX ); 4812 add_assoc_long( return_value, "n_cs_precedes", CHAR_MAX ); 4813 add_assoc_long( return_value, "n_sep_by_space", CHAR_MAX ); 4814 add_assoc_long( return_value, "p_sign_posn", CHAR_MAX ); 4815 add_assoc_long( return_value, "n_sign_posn", CHAR_MAX ); 4816#endif 4817 4818 zend_hash_update(Z_ARRVAL_P(return_value), "grouping", 9, &grouping, sizeof(zval *), NULL); 4819 zend_hash_update(Z_ARRVAL_P(return_value), "mon_grouping", 13, &mon_grouping, sizeof(zval *), NULL); 4820} 4821/* }}} */ 4822 4823/* {{{ proto int strnatcasecmp(string s1, string s2) 4824 Returns the result of case-insensitive string comparison using 'natural' algorithm */ 4825PHP_FUNCTION(strnatcasecmp) 4826{ 4827 php_strnatcmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); 4828} 4829/* }}} */ 4830 4831/* {{{ proto int substr_count(string haystack, string needle [, int offset [, int length]]) 4832 Returns the number of times a substring occurs in the string */ 4833PHP_FUNCTION(substr_count) 4834{ 4835 char *haystack, *needle; 4836 long offset = 0, length = 0; 4837 int ac = ZEND_NUM_ARGS(); 4838 int count = 0; 4839 int haystack_len, needle_len; 4840 char *p, *endp, cmp; 4841 4842 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|ll", &haystack, &haystack_len, &needle, &needle_len, &offset, &length) == FAILURE) { 4843 return; 4844 } 4845 4846 if (needle_len == 0) { 4847 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty substring"); 4848 RETURN_FALSE; 4849 } 4850 4851 p = haystack; 4852 endp = p + haystack_len; 4853 4854 if (offset < 0) { 4855 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset should be greater than or equal to 0"); 4856 RETURN_FALSE; 4857 } 4858 4859 if (offset > haystack_len) { 4860 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset value %ld exceeds string length", offset); 4861 RETURN_FALSE; 4862 } 4863 p += offset; 4864 4865 if (ac == 4) { 4866 4867 if (length <= 0) { 4868 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Length should be greater than 0"); 4869 RETURN_FALSE; 4870 } 4871 if (length > (haystack_len - offset)) { 4872 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Length value %ld exceeds string length", length); 4873 RETURN_FALSE; 4874 } 4875 endp = p + length; 4876 } 4877 4878 if (needle_len == 1) { 4879 cmp = needle[0]; 4880 4881 while ((p = memchr(p, cmp, endp - p))) { 4882 count++; 4883 p++; 4884 } 4885 } else { 4886 while ((p = php_memnstr(p, needle, needle_len, endp))) { 4887 p += needle_len; 4888 count++; 4889 } 4890 } 4891 4892 RETURN_LONG(count); 4893} 4894/* }}} */ 4895 4896/* {{{ proto string str_pad(string input, int pad_length [, string pad_string [, int pad_type]]) 4897 Returns input string padded on the left or right to specified length with pad_string */ 4898PHP_FUNCTION(str_pad) 4899{ 4900 /* Input arguments */ 4901 char *input; /* Input string */ 4902 int input_len; 4903 long pad_length; /* Length to pad to */ 4904 4905 /* Helper variables */ 4906 size_t num_pad_chars; /* Number of padding characters (total - input size) */ 4907 char *result = NULL; /* Resulting string */ 4908 int result_len = 0; /* Length of the resulting string */ 4909 char *pad_str_val = " "; /* Pointer to padding string */ 4910 int pad_str_len = 1; /* Length of the padding string */ 4911 long pad_type_val = STR_PAD_RIGHT; /* The padding type value */ 4912 int i, left_pad=0, right_pad=0; 4913 4914 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|sl", &input, &input_len, &pad_length, 4915 &pad_str_val, &pad_str_len, &pad_type_val) == FAILURE) { 4916 return; 4917 } 4918 4919 /* If resulting string turns out to be shorter than input string, 4920 we simply copy the input and return. */ 4921 if (pad_length <= 0 || (pad_length - input_len) <= 0) { 4922 RETURN_STRINGL(input, input_len, 1); 4923 } 4924 4925 if (pad_str_len == 0) { 4926 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Padding string cannot be empty"); 4927 return; 4928 } 4929 4930 if (pad_type_val < STR_PAD_LEFT || pad_type_val > STR_PAD_BOTH) { 4931 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Padding type has to be STR_PAD_LEFT, STR_PAD_RIGHT, or STR_PAD_BOTH"); 4932 return; 4933 } 4934 4935 num_pad_chars = pad_length - input_len; 4936 if (num_pad_chars >= INT_MAX) { 4937 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Padding length is too long"); 4938 return; 4939 } 4940 result = (char *)emalloc(input_len + num_pad_chars + 1); 4941 4942 /* We need to figure out the left/right padding lengths. */ 4943 switch (pad_type_val) { 4944 case STR_PAD_RIGHT: 4945 left_pad = 0; 4946 right_pad = num_pad_chars; 4947 break; 4948 4949 case STR_PAD_LEFT: 4950 left_pad = num_pad_chars; 4951 right_pad = 0; 4952 break; 4953 4954 case STR_PAD_BOTH: 4955 left_pad = num_pad_chars / 2; 4956 right_pad = num_pad_chars - left_pad; 4957 break; 4958 } 4959 4960 /* First we pad on the left. */ 4961 for (i = 0; i < left_pad; i++) 4962 result[result_len++] = pad_str_val[i % pad_str_len]; 4963 4964 /* Then we copy the input string. */ 4965 memcpy(result + result_len, input, input_len); 4966 result_len += input_len; 4967 4968 /* Finally, we pad on the right. */ 4969 for (i = 0; i < right_pad; i++) 4970 result[result_len++] = pad_str_val[i % pad_str_len]; 4971 4972 result[result_len] = '\0'; 4973 4974 RETURN_STRINGL(result, result_len, 0); 4975} 4976/* }}} */ 4977 4978/* {{{ proto mixed sscanf(string str, string format [, string ...]) 4979 Implements an ANSI C compatible sscanf */ 4980PHP_FUNCTION(sscanf) 4981{ 4982 zval ***args = NULL; 4983 char *str, *format; 4984 int str_len, format_len, result, num_args = 0; 4985 4986 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss*", &str, &str_len, &format, &format_len, 4987 &args, &num_args) == FAILURE) { 4988 return; 4989 } 4990 4991 result = php_sscanf_internal(str, format, num_args, args, 0, &return_value TSRMLS_CC); 4992 4993 if (args) { 4994 efree(args); 4995 } 4996 4997 if (SCAN_ERROR_WRONG_PARAM_COUNT == result) { 4998 WRONG_PARAM_COUNT; 4999 } 5000} 5001/* }}} */ 5002 5003static char rot13_from[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; 5004static char rot13_to[] = "nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM"; 5005 5006/* {{{ proto string str_rot13(string str) 5007 Perform the rot13 transform on a string */ 5008PHP_FUNCTION(str_rot13) 5009{ 5010 char *arg; 5011 int arglen; 5012 5013 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arglen) == FAILURE) { 5014 return; 5015 } 5016 5017 RETVAL_STRINGL(arg, arglen, 1); 5018 5019 php_strtr(Z_STRVAL_P(return_value), Z_STRLEN_P(return_value), rot13_from, rot13_to, 52); 5020} 5021/* }}} */ 5022 5023static void php_string_shuffle(char *str, long len TSRMLS_DC) /* {{{ */ 5024{ 5025 long n_elems, rnd_idx, n_left; 5026 char temp; 5027 /* The implementation is stolen from array_data_shuffle */ 5028 /* Thus the characteristics of the randomization are the same */ 5029 n_elems = len; 5030 5031 if (n_elems <= 1) { 5032 return; 5033 } 5034 5035 n_left = n_elems; 5036 5037 while (--n_left) { 5038 rnd_idx = php_rand(TSRMLS_C); 5039 RAND_RANGE(rnd_idx, 0, n_left, PHP_RAND_MAX); 5040 if (rnd_idx != n_left) { 5041 temp = str[n_left]; 5042 str[n_left] = str[rnd_idx]; 5043 str[rnd_idx] = temp; 5044 } 5045 } 5046} 5047/* }}} */ 5048 5049/* {{{ proto void str_shuffle(string str) 5050 Shuffles string. One permutation of all possible is created */ 5051PHP_FUNCTION(str_shuffle) 5052{ 5053 char *arg; 5054 int arglen; 5055 5056 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arglen) == FAILURE) { 5057 return; 5058 } 5059 5060 RETVAL_STRINGL(arg, arglen, 1); 5061 if (Z_STRLEN_P(return_value) > 1) { 5062 php_string_shuffle(Z_STRVAL_P(return_value), (long) Z_STRLEN_P(return_value) TSRMLS_CC); 5063 } 5064} 5065/* }}} */ 5066 5067/* {{{ proto mixed str_word_count(string str, [int format [, string charlist]]) 5068 Counts the number of words inside a string. If format of 1 is specified, 5069 then the function will return an array containing all the words 5070 found inside the string. If format of 2 is specified, then the function 5071 will return an associated array where the position of the word is the key 5072 and the word itself is the value. 5073 5074 For the purpose of this function, 'word' is defined as a locale dependent 5075 string containing alphabetic characters, which also may contain, but not start 5076 with "'" and "-" characters. 5077*/ 5078PHP_FUNCTION(str_word_count) 5079{ 5080 char *buf, *str, *char_list = NULL, *p, *e, *s, ch[256]; 5081 int str_len, char_list_len = 0, word_count = 0; 5082 long type = 0; 5083 5084 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ls", &str, &str_len, &type, &char_list, &char_list_len) == FAILURE) { 5085 return; 5086 } 5087 5088 switch(type) { 5089 case 1: 5090 case 2: 5091 array_init(return_value); 5092 if (!str_len) { 5093 return; 5094 } 5095 break; 5096 case 0: 5097 if (!str_len) { 5098 RETURN_LONG(0); 5099 } 5100 /* nothing to be done */ 5101 break; 5102 default: 5103 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid format value %ld", type); 5104 RETURN_FALSE; 5105 } 5106 5107 if (char_list) { 5108 php_charmask((unsigned char *)char_list, char_list_len, ch TSRMLS_CC); 5109 } 5110 5111 p = str; 5112 e = str + str_len; 5113 5114 /* first character cannot be ' or -, unless explicitly allowed by the user */ 5115 if ((*p == '\'' && (!char_list || !ch['\''])) || (*p == '-' && (!char_list || !ch['-']))) { 5116 p++; 5117 } 5118 /* last character cannot be -, unless explicitly allowed by the user */ 5119 if (*(e - 1) == '-' && (!char_list || !ch['-'])) { 5120 e--; 5121 } 5122 5123 while (p < e) { 5124 s = p; 5125 while (p < e && (isalpha((unsigned char)*p) || (char_list && ch[(unsigned char)*p]) || *p == '\'' || *p == '-')) { 5126 p++; 5127 } 5128 if (p > s) { 5129 switch (type) 5130 { 5131 case 1: 5132 buf = estrndup(s, (p-s)); 5133 add_next_index_stringl(return_value, buf, (p-s), 0); 5134 break; 5135 case 2: 5136 buf = estrndup(s, (p-s)); 5137 add_index_stringl(return_value, (s - str), buf, p-s, 0); 5138 break; 5139 default: 5140 word_count++; 5141 break; 5142 } 5143 } 5144 p++; 5145 } 5146 5147 if (!type) { 5148 RETURN_LONG(word_count); 5149 } 5150} 5151 5152/* }}} */ 5153 5154#if HAVE_STRFMON 5155/* {{{ proto string money_format(string format , float value) 5156 Convert monetary value(s) to string */ 5157PHP_FUNCTION(money_format) 5158{ 5159 int format_len = 0, str_len; 5160 char *format, *str, *p, *e; 5161 double value; 5162 zend_bool check = 0; 5163 5164 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sd", &format, &format_len, &value) == FAILURE) { 5165 return; 5166 } 5167 5168 p = format; 5169 e = p + format_len; 5170 while ((p = memchr(p, '%', (e - p)))) { 5171 if (*(p + 1) == '%') { 5172 p += 2; 5173 } else if (!check) { 5174 check = 1; 5175 p++; 5176 } else { 5177 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Only a single %%i or %%n token can be used"); 5178 RETURN_FALSE; 5179 } 5180 } 5181 5182 str_len = format_len + 1024; 5183 str = emalloc(str_len); 5184 if ((str_len = strfmon(str, str_len, format, value)) < 0) { 5185 efree(str); 5186 RETURN_FALSE; 5187 } 5188 str[str_len] = 0; 5189 5190 RETURN_STRINGL(erealloc(str, str_len + 1), str_len, 0); 5191} 5192/* }}} */ 5193#endif 5194 5195/* {{{ proto array str_split(string str [, int split_length]) 5196 Convert a string to an array. If split_length is specified, break the string down into chunks each split_length characters long. */ 5197PHP_FUNCTION(str_split) 5198{ 5199 char *str; 5200 int str_len; 5201 long split_length = 1; 5202 char *p; 5203 int n_reg_segments; 5204 5205 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &str, &str_len, &split_length) == FAILURE) { 5206 return; 5207 } 5208 5209 if (split_length <= 0) { 5210 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The length of each segment must be greater than zero"); 5211 RETURN_FALSE; 5212 } 5213 5214 array_init_size(return_value, ((str_len - 1) / split_length) + 1); 5215 5216 if (split_length >= str_len) { 5217 add_next_index_stringl(return_value, str, str_len, 1); 5218 return; 5219 } 5220 5221 n_reg_segments = str_len / split_length; 5222 p = str; 5223 5224 while (n_reg_segments-- > 0) { 5225 add_next_index_stringl(return_value, p, split_length, 1); 5226 p += split_length; 5227 } 5228 5229 if (p != (str + str_len)) { 5230 add_next_index_stringl(return_value, p, (str + str_len - p), 1); 5231 } 5232} 5233/* }}} */ 5234 5235/* {{{ proto array strpbrk(string haystack, string char_list) 5236 Search a string for any of a set of characters */ 5237PHP_FUNCTION(strpbrk) 5238{ 5239 char *haystack, *char_list; 5240 int haystack_len, char_list_len; 5241 char *haystack_ptr, *cl_ptr; 5242 5243 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &haystack, &haystack_len, &char_list, &char_list_len) == FAILURE) { 5244 RETURN_FALSE; 5245 } 5246 5247 if (!char_list_len) { 5248 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The character list cannot be empty"); 5249 RETURN_FALSE; 5250 } 5251 5252 for (haystack_ptr = haystack; haystack_ptr < (haystack + haystack_len); ++haystack_ptr) { 5253 for (cl_ptr = char_list; cl_ptr < (char_list + char_list_len); ++cl_ptr) { 5254 if (*cl_ptr == *haystack_ptr) { 5255 RETURN_STRINGL(haystack_ptr, (haystack + haystack_len - haystack_ptr), 1); 5256 } 5257 } 5258 } 5259 5260 RETURN_FALSE; 5261} 5262/* }}} */ 5263 5264/* {{{ proto int substr_compare(string main_str, string str, int offset [, int length [, bool case_sensitivity]]) 5265 Binary safe optionally case insensitive comparison of 2 strings from an offset, up to length characters */ 5266PHP_FUNCTION(substr_compare) 5267{ 5268 char *s1, *s2; 5269 int s1_len, s2_len; 5270 long offset, len=0; 5271 zend_bool cs=0; 5272 uint cmp_len; 5273 5274 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssl|lb", &s1, &s1_len, &s2, &s2_len, &offset, &len, &cs) == FAILURE) { 5275 RETURN_FALSE; 5276 } 5277 5278 if (ZEND_NUM_ARGS() >= 4 && len <= 0) { 5279 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The length must be greater than zero"); 5280 RETURN_FALSE; 5281 } 5282 5283 if (offset < 0) { 5284 offset = s1_len + offset; 5285 offset = (offset < 0) ? 0 : offset; 5286 } 5287 5288 if (offset >= s1_len) { 5289 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The start position cannot exceed initial string length"); 5290 RETURN_FALSE; 5291 } 5292 5293 if (len > s1_len - offset) { 5294 len = s1_len - offset; 5295 } 5296 5297 cmp_len = (uint) (len ? len : MAX(s2_len, (s1_len - offset))); 5298 5299 if (!cs) { 5300 RETURN_LONG(zend_binary_strncmp(s1 + offset, (s1_len - offset), s2, s2_len, cmp_len)); 5301 } else { 5302 RETURN_LONG(zend_binary_strncasecmp(s1 + offset, (s1_len - offset), s2, s2_len, cmp_len)); 5303 } 5304} 5305/* }}} */ 5306 5307/* 5308 * Local variables: 5309 * tab-width: 4 5310 * c-basic-offset: 4 5311 * End: 5312 * vim600: noet sw=4 ts=4 fdm=marker 5313 * vim<600: noet sw=4 ts=4 5314 */ 5315