PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/intl/idn - idn.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 53 75 70.7 %
Date: 2014-10-30 Functions: 7 7 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | PHP Version 7                                                        |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 2009 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             :    | Author: Pierre A. Joye <pierre@php.net>                              |
      16             :    |         Gustavo Lopes  <cataphract@php.net>                          |
      17             :    +----------------------------------------------------------------------+
      18             :  */
      19             : /* $Id$ */
      20             : 
      21             : /* {{{ includes */
      22             : #ifdef HAVE_CONFIG_H
      23             : #include "config.h"
      24             : #endif
      25             : 
      26             : #include <php.h>
      27             : 
      28             : #include <unicode/uidna.h>
      29             : #include <unicode/ustring.h>
      30             : #include "ext/standard/php_string.h"
      31             : 
      32             : #include "intl_error.h"
      33             : #include "intl_convert.h"
      34             : /* }}} */
      35             : 
      36             : #ifdef UIDNA_INFO_INITIALIZER
      37             : #define HAVE_46_API 1 /* has UTS#46 API (introduced in ICU 4.6) */
      38             : #endif
      39             : 
      40             : enum {
      41             :         INTL_IDN_VARIANT_2003 = 0,
      42             :         INTL_IDN_VARIANT_UTS46
      43             : };
      44             : 
      45             : /* {{{ grapheme_register_constants
      46             :  * Register API constants
      47             :  */
      48       20423 : void idn_register_constants( INIT_FUNC_ARGS )
      49             : {
      50             :         /* OPTIONS */
      51             : 
      52             :         /* Option to prohibit processing of unassigned codepoints in the input and
      53             :            do not check if the input conforms to STD-3 ASCII rules. */
      54       20423 :         REGISTER_LONG_CONSTANT("IDNA_DEFAULT", UIDNA_DEFAULT, CONST_CS | CONST_PERSISTENT);
      55             : 
      56             :         /* Option to allow processing of unassigned codepoints in the input */
      57       20423 :         REGISTER_LONG_CONSTANT("IDNA_ALLOW_UNASSIGNED", UIDNA_ALLOW_UNASSIGNED, CONST_CS | CONST_PERSISTENT);
      58             : 
      59             :         /* Option to check if input conforms to STD-3 ASCII rules */
      60       20423 :         REGISTER_LONG_CONSTANT("IDNA_USE_STD3_RULES", UIDNA_USE_STD3_RULES, CONST_CS | CONST_PERSISTENT);
      61             : 
      62             : #ifdef HAVE_46_API
      63             : 
      64             :         /* Option to check for whether the input conforms to the BiDi rules.
      65             :          * Ignored by the IDNA2003 implementation. (IDNA2003 always performs a BiDi check.) */
      66             :         REGISTER_LONG_CONSTANT("IDNA_CHECK_BIDI", UIDNA_CHECK_BIDI, CONST_CS | CONST_PERSISTENT);
      67             : 
      68             :         /* Option to check for whether the input conforms to the CONTEXTJ rules.
      69             :          * Ignored by the IDNA2003 implementation. (The CONTEXTJ check is new in IDNA2008.) */
      70             :         REGISTER_LONG_CONSTANT("IDNA_CHECK_CONTEXTJ", UIDNA_CHECK_CONTEXTJ, CONST_CS | CONST_PERSISTENT);
      71             : 
      72             :         /* Option for nontransitional processing in ToASCII().
      73             :          * By default, ToASCII() uses transitional processing.
      74             :          * Ignored by the IDNA2003 implementation. */
      75             :         REGISTER_LONG_CONSTANT("IDNA_NONTRANSITIONAL_TO_ASCII", UIDNA_NONTRANSITIONAL_TO_ASCII, CONST_CS | CONST_PERSISTENT);
      76             : 
      77             :         /* Option for nontransitional processing in ToUnicode().
      78             :          * By default, ToUnicode() uses transitional processing.
      79             :          * Ignored by the IDNA2003 implementation. */
      80             :         REGISTER_LONG_CONSTANT("IDNA_NONTRANSITIONAL_TO_UNICODE", UIDNA_NONTRANSITIONAL_TO_UNICODE, CONST_CS | CONST_PERSISTENT);
      81             : #endif
      82             : 
      83             :         /* VARIANTS */
      84       20423 :         REGISTER_LONG_CONSTANT("INTL_IDNA_VARIANT_2003", INTL_IDN_VARIANT_2003, CONST_CS | CONST_PERSISTENT);
      85             : #ifdef HAVE_46_API
      86             :         REGISTER_LONG_CONSTANT("INTL_IDNA_VARIANT_UTS46", INTL_IDN_VARIANT_UTS46, CONST_CS | CONST_PERSISTENT);
      87             : #endif
      88             : 
      89             : #ifdef HAVE_46_API
      90             :         /* PINFO ERROR CODES */
      91             :         REGISTER_LONG_CONSTANT("IDNA_ERROR_EMPTY_LABEL", UIDNA_ERROR_EMPTY_LABEL, CONST_CS | CONST_PERSISTENT);
      92             :         REGISTER_LONG_CONSTANT("IDNA_ERROR_LABEL_TOO_LONG", UIDNA_ERROR_LABEL_TOO_LONG, CONST_CS | CONST_PERSISTENT);
      93             :         REGISTER_LONG_CONSTANT("IDNA_ERROR_DOMAIN_NAME_TOO_LONG", UIDNA_ERROR_DOMAIN_NAME_TOO_LONG, CONST_CS | CONST_PERSISTENT);
      94             :         REGISTER_LONG_CONSTANT("IDNA_ERROR_LEADING_HYPHEN", UIDNA_ERROR_LEADING_HYPHEN, CONST_CS | CONST_PERSISTENT);
      95             :         REGISTER_LONG_CONSTANT("IDNA_ERROR_TRAILING_HYPHEN", UIDNA_ERROR_TRAILING_HYPHEN, CONST_CS | CONST_PERSISTENT);
      96             :         REGISTER_LONG_CONSTANT("IDNA_ERROR_HYPHEN_3_4", UIDNA_ERROR_HYPHEN_3_4, CONST_CS | CONST_PERSISTENT);
      97             :         REGISTER_LONG_CONSTANT("IDNA_ERROR_LEADING_COMBINING_MARK", UIDNA_ERROR_LEADING_COMBINING_MARK, CONST_CS | CONST_PERSISTENT);
      98             :         REGISTER_LONG_CONSTANT("IDNA_ERROR_DISALLOWED", UIDNA_ERROR_DISALLOWED, CONST_CS | CONST_PERSISTENT);
      99             :         REGISTER_LONG_CONSTANT("IDNA_ERROR_PUNYCODE", UIDNA_ERROR_PUNYCODE, CONST_CS | CONST_PERSISTENT);
     100             :         REGISTER_LONG_CONSTANT("IDNA_ERROR_LABEL_HAS_DOT", UIDNA_ERROR_LABEL_HAS_DOT, CONST_CS | CONST_PERSISTENT);
     101             :         REGISTER_LONG_CONSTANT("IDNA_ERROR_INVALID_ACE_LABEL", UIDNA_ERROR_INVALID_ACE_LABEL, CONST_CS | CONST_PERSISTENT);
     102             :         REGISTER_LONG_CONSTANT("IDNA_ERROR_BIDI", UIDNA_ERROR_BIDI, CONST_CS | CONST_PERSISTENT);
     103             :         REGISTER_LONG_CONSTANT("IDNA_ERROR_CONTEXTJ", UIDNA_ERROR_CONTEXTJ, CONST_CS | CONST_PERSISTENT);
     104             : #endif
     105       20423 : }
     106             : /* }}} */
     107             : 
     108             : enum {
     109             :         INTL_IDN_TO_ASCII = 0,
     110             :         INTL_IDN_TO_UTF8
     111             : };
     112             : 
     113             : /* like INTL_CHECK_STATUS, but as a function and varying the name of the func */
     114           2 : static int php_intl_idn_check_status(UErrorCode err, const char *msg, int mode TSRMLS_DC)
     115             : {
     116           2 :         intl_error_set_code(NULL, err TSRMLS_CC);
     117           2 :         if (U_FAILURE(err)) {
     118             :                 char *buff;
     119           2 :                 spprintf(&buff, 0, "%s: %s",
     120             :                         mode == INTL_IDN_TO_ASCII ? "idn_to_ascii" : "idn_to_utf8",
     121             :                         msg);
     122           2 :                 intl_error_set_custom_msg(NULL, buff, 1 TSRMLS_CC);
     123           2 :                 efree(buff);
     124           2 :                 return FAILURE;
     125             :         }
     126             : 
     127           0 :         return SUCCESS;
     128             : }
     129             : 
     130           2 : static inline void php_intl_bad_args(const char *msg, int mode TSRMLS_DC)
     131             : {
     132           2 :         php_intl_idn_check_status(U_ILLEGAL_ARGUMENT_ERROR, msg, mode TSRMLS_CC);
     133           2 : }
     134             : 
     135             : #ifdef HAVE_46_API
     136             : static void php_intl_idn_to_46(INTERNAL_FUNCTION_PARAMETERS,
     137             :                 const char *domain, int domain_len, uint32_t option, int mode, zval *idna_info)
     138             : {
     139             :         UErrorCode        status = U_ZERO_ERROR;
     140             :         UIDNA             *uts46;
     141             :         int32_t           len;
     142             :         int32_t           buffer_capac = 255; /* no domain name may exceed this */
     143             :         zend_string       *buffer = zend_string_alloc(buffer_capac, 0);
     144             :         UIDNAInfo         info = UIDNA_INFO_INITIALIZER;
     145             :         int                       buffer_used = 0;
     146             :         
     147             :         uts46 = uidna_openUTS46(option, &status);
     148             :         if (php_intl_idn_check_status(status, "failed to open UIDNA instance",
     149             :                         mode TSRMLS_CC) == FAILURE) {
     150             :                 zend_string_free(buffer);
     151             :                 RETURN_FALSE;
     152             :         }
     153             : 
     154             :         if (mode == INTL_IDN_TO_ASCII) {
     155             :                 len = uidna_nameToASCII_UTF8(uts46, domain, (int32_t)domain_len,
     156             :                                 buffer->val, buffer_capac, &info, &status);
     157             :         } else {
     158             :                 len = uidna_nameToUnicodeUTF8(uts46, domain, (int32_t)domain_len,
     159             :                                 buffer->val, buffer_capac, &info, &status);
     160             :         }
     161             :         if (php_intl_idn_check_status(status, "failed to convert name",
     162             :                         mode TSRMLS_CC) == FAILURE) {
     163             :                 uidna_close(uts46);
     164             :                 zend_string_free(buffer);
     165             :                 RETURN_FALSE;
     166             :         }
     167             :         if (len >= 255) {
     168             :                 php_error_docref(NULL TSRMLS_CC, E_ERROR, "ICU returned an unexpected length");
     169             :         }
     170             : 
     171             :         buffer->val[len] = '\0';
     172             :         buffer->len = len;
     173             : 
     174             :         if (info.errors == 0) {
     175             :                 RETVAL_STR(buffer);
     176             :                 buffer_used = 1;
     177             :         } else {
     178             :                 RETVAL_FALSE;
     179             :         }
     180             : 
     181             :         if (idna_info) {
     182             :                 if (buffer_used) { /* used in return_value then */
     183             :                         zval_addref_p(return_value);
     184             :                         add_assoc_zval_ex(idna_info, "result", sizeof("result")-1, return_value);
     185             :                 } else {
     186             :                         zval zv;
     187             :                         ZVAL_NEW_STR(&zv, buffer);
     188             :                         buffer_used = 1;
     189             :                         add_assoc_zval_ex(idna_info, "result", sizeof("result")-1, &zv);
     190             :                 }
     191             :                 add_assoc_bool_ex(idna_info, "isTransitionalDifferent",
     192             :                                 sizeof("isTransitionalDifferent")-1, info.isTransitionalDifferent);
     193             :                 add_assoc_long_ex(idna_info, "errors", sizeof("errors")-1, (zend_long)info.errors);
     194             :         }
     195             : 
     196             :         if (!buffer_used) {
     197             :                 zend_string_free(buffer);
     198             :         }
     199             : 
     200             :         uidna_close(uts46);
     201             : }
     202             : #endif
     203             : 
     204           2 : static void php_intl_idn_to(INTERNAL_FUNCTION_PARAMETERS,
     205             :                 const char *domain, int domain_len, uint32_t option, int mode)
     206             : {
     207           2 :         UChar* ustring = NULL;
     208           2 :         int ustring_len = 0;
     209             :         UErrorCode status;
     210             :         char     *converted_utf8;
     211             :         int32_t   converted_utf8_len;
     212             :         UChar     converted[MAXPATHLEN];
     213             :         int32_t   converted_ret_len;
     214             : 
     215             :         /* convert the string to UTF-16. */
     216           2 :         status = U_ZERO_ERROR;
     217           2 :         intl_convert_utf8_to_utf16(&ustring, &ustring_len, domain, domain_len, &status);
     218             : 
     219           2 :         if (U_FAILURE(status)) {
     220           0 :                 intl_error_set_code(NULL, status TSRMLS_CC);
     221             : 
     222             :                 /* Set error messages. */
     223           0 :                 intl_error_set_custom_msg( NULL, "Error converting input string to UTF-16", 0 TSRMLS_CC );
     224           0 :                 if (ustring) {
     225           0 :                         efree(ustring);
     226             :                 }
     227           0 :                 RETURN_FALSE;
     228             :         } else {
     229             :                 UParseError parse_error;
     230             : 
     231           2 :                 status = U_ZERO_ERROR;
     232           2 :                 if (mode == INTL_IDN_TO_ASCII) {
     233           1 :                         converted_ret_len = uidna_IDNToASCII(ustring, ustring_len, converted, MAXPATHLEN, (int32_t)option, &parse_error, &status);
     234             :                 } else {
     235           1 :                         converted_ret_len = uidna_IDNToUnicode(ustring, ustring_len, converted, MAXPATHLEN, (int32_t)option, &parse_error, &status);
     236             :                 }
     237           2 :                 efree(ustring);
     238             : 
     239           2 :                 if (U_FAILURE(status)) {
     240           0 :                         intl_error_set( NULL, status, "idn_to_ascii: cannot convert to ASCII", 0 TSRMLS_CC );
     241           0 :                         RETURN_FALSE;
     242             :                 }
     243             : 
     244           2 :                 status = U_ZERO_ERROR;
     245           2 :                 intl_convert_utf16_to_utf8(&converted_utf8, &converted_utf8_len, converted, converted_ret_len, &status);
     246             : 
     247           2 :                 if (U_FAILURE(status)) {
     248             :                         /* Set global error code. */
     249           0 :                         intl_error_set_code(NULL, status TSRMLS_CC);
     250             : 
     251             :                         /* Set error messages. */
     252           0 :                         intl_error_set_custom_msg( NULL, "Error converting output string to UTF-8", 0 TSRMLS_CC );
     253           0 :                         efree(converted_utf8);
     254           0 :                         RETURN_FALSE;
     255             :                 }
     256             :         }
     257             : 
     258             :         /* return the allocated string, not a duplicate */
     259           4 :         RETVAL_STRINGL(((char *)converted_utf8), converted_utf8_len);
     260             :         //????
     261           2 :         efree(converted_utf8);
     262             : }
     263             : 
     264           4 : static void php_intl_idn_handoff(INTERNAL_FUNCTION_PARAMETERS, int mode)
     265             : {
     266             :         char *domain;
     267             :         size_t domain_len;
     268           4 :         zend_long option = 0,
     269           4 :                  variant = INTL_IDN_VARIANT_2003;
     270           4 :         zval *idna_info = NULL;
     271             : 
     272           4 :         intl_error_reset(NULL TSRMLS_CC);
     273             : 
     274           4 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|llz/",
     275             :                         &domain, &domain_len, &option, &variant, &idna_info) == FAILURE) {
     276           2 :                 php_intl_bad_args("bad arguments", mode TSRMLS_CC);
     277           2 :                 RETURN_NULL(); /* don't set FALSE because that's not the way it was before... */
     278             :         }
     279             : 
     280             : #ifdef HAVE_46_API
     281             :         if (variant != INTL_IDN_VARIANT_2003 && variant != INTL_IDN_VARIANT_UTS46) {
     282             :                 php_intl_bad_args("invalid variant, must be one of {"
     283             :                         "INTL_IDNA_VARIANT_2003, INTL_IDNA_VARIANT_UTS46}", mode TSRMLS_CC);
     284             :                 RETURN_FALSE;
     285             :         }
     286             : #else
     287           2 :         if (variant != INTL_IDN_VARIANT_2003) {
     288           0 :                 php_intl_bad_args("invalid variant, PHP was compiled against "
     289             :                         "an old version of ICU and only supports INTL_IDN_VARIANT_2003",
     290             :                         mode TSRMLS_CC);
     291           0 :                 RETURN_FALSE;
     292             :         }
     293             : #endif
     294             : 
     295           2 :         if (domain_len < 1) {
     296           0 :                 php_intl_bad_args("empty domain name", mode TSRMLS_CC);
     297           0 :                 RETURN_FALSE;
     298             :         }
     299           2 :         if (domain_len > INT32_MAX - 1) {
     300           0 :                 php_intl_bad_args("domain name too large", mode TSRMLS_CC);
     301           0 :                 RETURN_FALSE;
     302             :         }
     303             :         /* don't check options; it wasn't checked before */
     304             : 
     305           2 :         if (idna_info != NULL) {
     306           0 :                 if (variant == INTL_IDN_VARIANT_2003) {
     307           0 :                         php_error_docref0(NULL TSRMLS_CC, E_NOTICE,
     308             :                                 "4 arguments were provided, but INTL_IDNA_VARIANT_2003 only "
     309             :                                 "takes 3 - extra argument ignored");
     310             :                 } else {
     311           0 :                         zval_dtor(idna_info);
     312           0 :                         array_init(idna_info);
     313             :                 }
     314             :         }
     315             :         
     316           2 :         if (variant == INTL_IDN_VARIANT_2003) {
     317           2 :                 php_intl_idn_to(INTERNAL_FUNCTION_PARAM_PASSTHRU,
     318             :                                 domain, domain_len, (uint32_t)option, mode);
     319             :         }
     320             : #ifdef HAVE_46_API
     321             :         else {
     322             :                 php_intl_idn_to_46(INTERNAL_FUNCTION_PARAM_PASSTHRU, domain, domain_len,
     323             :                                 (uint32_t)option, mode, idna_info);
     324             :         }
     325             : #endif
     326             : }
     327             : 
     328             : /* {{{ proto int idn_to_ascii(string domain[, int options[, int variant[, array &idna_info]]])
     329             :    Converts an Unicode domain to ASCII representation, as defined in the IDNA RFC */
     330           2 : PHP_FUNCTION(idn_to_ascii)
     331             : {
     332           2 :         php_intl_idn_handoff(INTERNAL_FUNCTION_PARAM_PASSTHRU, INTL_IDN_TO_ASCII);
     333           2 : }
     334             : /* }}} */
     335             : 
     336             : 
     337             : /* {{{ proto int idn_to_utf8(string domain[, int options[, int variant[, array &idna_info]]])
     338             :    Converts an ASCII representation of the domain to Unicode (UTF-8), as defined in the IDNA RFC */
     339           2 : PHP_FUNCTION(idn_to_utf8)
     340             : {
     341           2 :         php_intl_idn_handoff(INTERNAL_FUNCTION_PARAM_PASSTHRU, INTL_IDN_TO_UTF8);
     342           2 : }
     343             : /* }}} */
     344             : 
     345             : 
     346             : /*
     347             :  * Local variables:
     348             :  * tab-width: 4
     349             :  * c-basic-offset: 4
     350             :  * End:
     351             :  * vim600: fdm=marker
     352             :  * vim: noet sw=4 ts=4
     353             :  */

Generated by: LCOV version 1.10

Generated at Thu, 30 Oct 2014 07:41:32 +0000 (27 hours ago)

Copyright © 2005-2014 The PHP Group
All rights reserved.