diff options
author | yehudah <yehudah@b8457f37-d9ea-0310-8a92-e5e31aec5664> | 2017-11-15 07:56:14 +0000 |
---|---|---|
committer | yehudah <yehudah@b8457f37-d9ea-0310-8a92-e5e31aec5664> | 2017-11-15 07:56:14 +0000 |
commit | fa49f47e2f3db3115a9af66ebd404bb66d0c520b (patch) | |
tree | 93ac07583b93af5012faaf84df614aa52124e688 | |
parent | 373f5e27dcb5b78d5d5af54739b17466f4dcf1ab (diff) | |
download | Post-SMTP-fa49f47e2f3db3115a9af66ebd404bb66d0c520b.zip |
* Fixed: IP detection error in some web hosts
* Fixed: Link open in new page attribute = _blank
* Fixed: Replace deprecated PHP 7 functions.
* Temp: Missconfigured certificate errors
* Updated: Validator TLD's list
git-svn-id: https://plugins.svn.wordpress.org/post-smtp/trunk@1766753 b8457f37-d9ea-0310-8a92-e5e31aec5664
-rw-r--r-- | Postman/Postman-Email-Log/PostmanEmailLogController.php | 31 | ||||
-rw-r--r-- | Postman/Postman-Email-Log/PostmanEmailLogView.php | 237 | ||||
-rw-r--r-- | Postman/Postman-Mail/Zend-1.12.10/Validate/Hostname.php | 3928 | ||||
-rw-r--r-- | Postman/Postman.php | 22 | ||||
-rw-r--r-- | Postman/PostmanAdminController.php | 2 | ||||
-rw-r--r-- | Postman/PostmanPluginFeedback.php | 131 | ||||
-rw-r--r-- | Postman/PostmanViewController.php | 10 | ||||
-rw-r--r-- | postman-smtp.php | 1 | ||||
-rw-r--r-- | readme.txt | 4 | ||||
-rw-r--r-- | script/feedback/feedback.js | 73 | ||||
-rw-r--r-- | script/postman.js | 4 | ||||
-rw-r--r-- | style/postman-email-log.css | 363 | ||||
-rw-r--r-- | style/postman.css | 6 |
13 files changed, 3078 insertions, 1734 deletions
diff --git a/Postman/Postman-Email-Log/PostmanEmailLogController.php b/Postman/Postman-Email-Log/PostmanEmailLogController.php index 5df618f..1cdbee3 100644 --- a/Postman/Postman-Email-Log/PostmanEmailLogController.php +++ b/Postman/Postman-Email-Log/PostmanEmailLogController.php @@ -338,11 +338,42 @@ class PostmanEmailLogController { echo __( 'This is a record of deliveries made to the mail server. It does not neccessarily indicate sucessful delivery to the recipient.', Postman::TEXT_DOMAIN )?></p> </div> + <?php + $from_date = isset( $_POST['from_date'] ) ? sanitize_text_field( $_POST['from_date'] ) : ''; + $to_date = isset( $_POST['to_date'] ) ? sanitize_text_field( $_POST['to_date'] ) : ''; + $search = isset( $_POST['search'] ) ? sanitize_text_field( $_POST['search'] ) : ''; + ?> + + <form id="postman-email-log-filter" method="post"> + <div id="email-log-filter"> + <div class="form-control"> + <label for="from_date"><?php _e( 'From Date', Postman::TEXT_DOMAIN ); ?></label> + <input id="from_date" class="email-log-date" value="<?php echo $from_date; ?>" type="text" name="from_date" placeholder="<?php _e( 'From Date', Postman::TEXT_DOMAIN ); ?>"> + </div> + <div class="form-control"> + <label for="to_date"><?php _e( 'To Date', Postman::TEXT_DOMAIN ); ?></label> + <input id="to_date" class="email-log-date" value="<?php echo $to_date; ?>" type="text" name="to_date" placeholder="<?php _e( 'To Date', Postman::TEXT_DOMAIN ); ?>"> + </div> + <div class="form-control"> + <label for="search"><?php _e( 'Search', Postman::TEXT_DOMAIN ); ?></label> + <input id="search" type="text" name="search" value="<?php echo $search; ?>" placeholder="<?php _e( 'Search', Postman::TEXT_DOMAIN ); ?>"> + </div> + <div class="form-control"> + <button type="submit" name="filter" class="button button-primary"><?php _e( 'Filter', Postman::TEXT_DOMAIN ); ?></button> + </div> + + <div class="form-control"> + <!-- <button type="submit" name="export_email_logs" class="button button-primary">Export To CSV</button> --> + </div> + </div> + </form> + <!-- Forms are NOT created automatically, so you need to wrap the table in one to use features like bulk actions --> <form id="movies-filter" method="get"> <!-- For plugins, we also need to ensure that the form posts back to our current page --> <input type="hidden" name="page" value="<?php echo filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING ); ?>" /> + <!-- Now we can render the completed list table --> <?php $testListTable->display()?> </form> diff --git a/Postman/Postman-Email-Log/PostmanEmailLogView.php b/Postman/Postman-Email-Log/PostmanEmailLogView.php index ef06a29..df885cd 100644 --- a/Postman/Postman-Email-Log/PostmanEmailLogView.php +++ b/Postman/Postman-Email-Log/PostmanEmailLogView.php @@ -2,14 +2,13 @@ /** * See http://wpengineer.com/2426/wp_list_table-a-step-by-step-guide/ - * */ -if (! class_exists ( 'WP_List_Table' )) { - require_once (ABSPATH . 'wp-admin/includes/class-wp-list-table.php'); +if ( ! class_exists( 'WP_List_Table' ) ) { + require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' ); } class PostmanEmailLogView extends WP_List_Table { private $logger; - + /** * ************************************************************************ * REQUIRED. @@ -18,16 +17,16 @@ class PostmanEmailLogView extends WP_List_Table { * ************************************************************************* */ function __construct() { - $this->logger = new PostmanLogger ( get_class ( $this ) ); - + $this->logger = new PostmanLogger( get_class( $this ) ); + // Set parent defaults - parent::__construct ( array ( + parent::__construct( array( 'singular' => 'email_log_entry', // singular name of the listed records 'plural' => 'email_log_entries', // plural name of the listed records - 'ajax' => false + 'ajax' => false, ) ); // does this table support ajax? } - + /** * ************************************************************************ * Recommended. @@ -54,16 +53,16 @@ class PostmanEmailLogView extends WP_List_Table { * @return string Text or HTML to be placed inside the column <td> * ************************************************************************ */ - function column_default($item, $column_name) { - switch ($column_name) { + function column_default( $item, $column_name ) { + switch ( $column_name ) { case 'date' : case 'status' : - return $item [$column_name]; + return $item [ $column_name ]; default : - return print_r ( $item, true ); // Show the whole array for troubleshooting purposes + return print_r( $item, true ); // Show the whole array for troubleshooting purposes } } - + /** * ************************************************************************ * Recommended. @@ -77,48 +76,47 @@ class PostmanEmailLogView extends WP_List_Table { * should be an associative array formatted as 'slug'=>'link html' - and you * will need to generate the URLs yourself. You could even ensure the links * - * * @see WP_List_Table::::single_row_columns() * @param array $item * A singular item (one full row's worth of data) * @return string Text to be placed inside the column <td> (movie title only) * ************************************************************************ */ - function column_title($item) { - + function column_title( $item ) { + // Build row actions $iframeUri = 'admin-post.php?page=postman_email_log&action=%s&email=%s&TB_iframe=true&width=700&height=550'; - $deleteUrl = wp_nonce_url ( admin_url ( sprintf ( 'admin-post.php?page=postman_email_log&action=%s&email=%s', 'delete', $item ['ID'] ) ), 'delete_email_log_item_' . $item ['ID'] ); - $viewUrl = admin_url ( sprintf ( $iframeUri, 'view', $item ['ID'] ) ); - $transcriptUrl = admin_url ( sprintf ( $iframeUri, 'transcript', $item ['ID'] ) ); - $resendUrl = admin_url ( sprintf ( $iframeUri, 'resend', $item ['ID'] ) ); - - $meta_values = get_post_meta ( $item ['ID'] ); - - $actions = array ( - 'delete' => sprintf ( '<a href="%s">%s</a>', $deleteUrl, _x ( 'Delete', 'Delete an item from the email log', Postman::TEXT_DOMAIN ) ), - 'view' => sprintf ( '<a href="%s" class="thickbox">%s</a>', $viewUrl, _x ( 'View', 'View an item from the email log', Postman::TEXT_DOMAIN ) ) + $deleteUrl = wp_nonce_url( admin_url( sprintf( 'admin-post.php?page=postman_email_log&action=%s&email=%s', 'delete', $item ['ID'] ) ), 'delete_email_log_item_' . $item ['ID'] ); + $viewUrl = admin_url( sprintf( $iframeUri, 'view', $item ['ID'] ) ); + $transcriptUrl = admin_url( sprintf( $iframeUri, 'transcript', $item ['ID'] ) ); + $resendUrl = admin_url( sprintf( $iframeUri, 'resend', $item ['ID'] ) ); + + $meta_values = get_post_meta( $item ['ID'] ); + + $actions = array( + 'delete' => sprintf( '<a href="%s">%s</a>', $deleteUrl, _x( 'Delete', 'Delete an item from the email log', Postman::TEXT_DOMAIN ) ), + 'view' => sprintf( '<a href="%s" class="thickbox">%s</a>', $viewUrl, _x( 'View', 'View an item from the email log', Postman::TEXT_DOMAIN ) ), ); - - if (! empty ( $meta_values ['session_transcript'] [0] )) { - $actions ['transcript'] = sprintf ( '<a href="%1$s" class="thickbox">%2$s</a>', $transcriptUrl, __ ( 'Session Transcript', Postman::TEXT_DOMAIN ) ); + + if ( ! empty( $meta_values ['session_transcript'] [0] ) ) { + $actions ['transcript'] = sprintf( '<a href="%1$s" class="thickbox">%2$s</a>', $transcriptUrl, __( 'Session Transcript', Postman::TEXT_DOMAIN ) ); } else { - $actions ['transcript'] = sprintf ( '%2$s', $transcriptUrl, __ ( 'Session Transcript', Postman::TEXT_DOMAIN ) ); + $actions ['transcript'] = sprintf( '%2$s', $transcriptUrl, __( 'Session Transcript', Postman::TEXT_DOMAIN ) ); } - if (! (empty ( $meta_values ['original_to'] [0] ) && empty ( $meta_values ['originalHeaders'] [0] ))) { + if ( ! (empty( $meta_values ['original_to'] [0] ) && empty( $meta_values ['originalHeaders'] [0] )) ) { // $actions ['resend'] = sprintf ( '<a href="%s">%s</a>', $resendUrl, __ ( 'Resend', Postman::TEXT_DOMAIN ) ); - $actions ['resend'] = sprintf ( '<span id="%3$s"><a href="javascript:postman_resend_email(%1$s);">%2$s</a></span>', $item ['ID'], __ ( 'Resend', Postman::TEXT_DOMAIN ), 'resend-' . $item ['ID'] ); + $actions ['resend'] = sprintf( '<span id="%3$s"><a href="javascript:postman_resend_email(%1$s);">%2$s</a></span>', $item ['ID'], __( 'Resend', Postman::TEXT_DOMAIN ), 'resend-' . $item ['ID'] ); } else { - $actions ['resend'] = sprintf ( '%2$s', $resendUrl, __ ( 'Resend', Postman::TEXT_DOMAIN ) ); + $actions ['resend'] = sprintf( '%2$s', $resendUrl, __( 'Resend', Postman::TEXT_DOMAIN ) ); } - + // Return the title contents - return sprintf ( '%1$s %3$s', - /*$1%s*/ $item ['title'], - /*$2%s*/ $item ['ID'], - /*$3%s*/ $this->row_actions ( $actions ) ); + return sprintf( '%1$s %3$s', + /*$1%s*/ $item ['title'], + /*$2%s*/ $item ['ID'], + /*$3%s*/ $this->row_actions( $actions ) ); } - + /** * ************************************************************************ * REQUIRED if displaying checkboxes or using bulk actions! The 'cb' column @@ -132,13 +130,13 @@ class PostmanEmailLogView extends WP_List_Table { * @return string Text to be placed inside the column <td> (movie title only) * ************************************************************************ */ - function column_cb($item) { - return sprintf ( '<input type="checkbox" name="%1$s[]" value="%2$s" />', - /*$1%s*/ $this->_args ['singular'], // Let's simply repurpose the table's singular label ("movie") - /* $2%s */ + function column_cb( $item ) { + return sprintf( '<input type="checkbox" name="%1$s[]" value="%2$s" />', + /*$1%s*/ $this->_args ['singular'], // Let's simply repurpose the table's singular label ("movie") + /* $2%s */ $item ['ID'] ); // The value of the checkbox should be the record's id } - + /** * ************************************************************************ * REQUIRED! This method dictates the table's columns and titles. @@ -156,15 +154,15 @@ class PostmanEmailLogView extends WP_List_Table { * ************************************************************************ */ function get_columns() { - $columns = array ( + $columns = array( 'cb' => '<input type="checkbox" />', // Render a checkbox instead of text - 'title' => _x ( 'Subject', 'What is the subject of this message?', Postman::TEXT_DOMAIN ), - 'status' => __ ( 'Status', Postman::TEXT_DOMAIN ), - 'date' => _x ( 'Delivery Time', 'When was this email sent?', Postman::TEXT_DOMAIN ) + 'title' => _x( 'Subject', 'What is the subject of this message?', Postman::TEXT_DOMAIN ), + 'status' => __( 'Status', Postman::TEXT_DOMAIN ), + 'date' => _x( 'Delivery Time', 'When was this email sent?', Postman::TEXT_DOMAIN ), ); return $columns; } - + /** * ************************************************************************ * Optional. @@ -183,24 +181,24 @@ class PostmanEmailLogView extends WP_List_Table { * ************************************************************************ */ function get_sortable_columns() { - return array (); - $sortable_columns = array ( - 'title' => array ( + return array(); + $sortable_columns = array( + 'title' => array( 'title', - false + false, ), // true means it's already sorted - 'status' => array ( + 'status' => array( 'status', - false + false, ), - 'date' => array ( + 'date' => array( 'date', - false - ) + false, + ), ); return $sortable_columns; } - + /** * ************************************************************************ * Optional. @@ -219,12 +217,12 @@ class PostmanEmailLogView extends WP_List_Table { * ************************************************************************ */ function get_bulk_actions() { - $actions = array ( - 'bulk_delete' => _x ( 'Delete', 'Delete an item from the email log', Postman::TEXT_DOMAIN ) + $actions = array( + 'bulk_delete' => _x( 'Delete', 'Delete an item from the email log', Postman::TEXT_DOMAIN ), ); return $actions; } - + /** * ************************************************************************ * Optional. @@ -236,7 +234,7 @@ class PostmanEmailLogView extends WP_List_Table { */ function process_bulk_action() { } - + /** * ************************************************************************ * REQUIRED! This is where you prepare your data for display. @@ -256,12 +254,12 @@ class PostmanEmailLogView extends WP_List_Table { * ************************************************************************ */ function prepare_items() { - + /** * First, lets decide how many records per page to show */ $per_page = 10; - + /** * REQUIRED. * Now we need to define our column headers. This includes a complete @@ -270,10 +268,10 @@ class PostmanEmailLogView extends WP_List_Table { * can be defined in another method (as we've done here) before being * used to build the value for our _column_headers property. */ - $columns = $this->get_columns (); - $hidden = array (); - $sortable = $this->get_sortable_columns (); - + $columns = $this->get_columns(); + $hidden = array(); + $sortable = $this->get_sortable_columns(); + /** * REQUIRED. * Finally, we build an array to be used by the class for column @@ -281,19 +279,19 @@ class PostmanEmailLogView extends WP_List_Table { * 3 other arrays. One for all columns, one for hidden columns, and one * for sortable columns. */ - $this->_column_headers = array ( + $this->_column_headers = array( $columns, $hidden, - $sortable + $sortable, ); - + /** * Optional. * You can handle your bulk actions however you see fit. In this * case, we'll handle them within our package just to keep things clean. */ - $this->process_bulk_action (); - + $this->process_bulk_action(); + /** * Instead of querying a database, we're going to fetch the example data * property we created for use in this plugin. @@ -304,44 +302,60 @@ class PostmanEmailLogView extends WP_List_Table { * use sort and pagination data to build a custom query instead, as you'll * be able to use your precisely-queried data immediately. */ - $data = array (); - $args = array ( + $data = array(); + $args = array( 'posts_per_page' => 1000, 'offset' => 0, - 'category' => '', - 'category_name' => '', 'orderby' => 'date', 'order' => 'DESC', - 'include' => '', - 'exclude' => '', - 'meta_key' => '', - 'meta_value' => '', 'post_type' => PostmanEmailLogPostType::POSTMAN_CUSTOM_POST_TYPE_SLUG, - 'post_mime_type' => '', - 'post_parent' => '', 'post_status' => 'private', - 'suppress_filters' => true + 'suppress_filters' => true, ); - $posts = get_posts ( $args ); - foreach ( $posts as $post ) { + + if ( isset( $_POST['from_date'] ) && ! empty( $_POST['from_date'] ) ) { + $from_date = sanitize_text_field( $_POST['from_date'] ); + + $args['date_query']['after'] = $from_date; + $args['date_query']['inclusive'] = false; + } + + if ( isset( $_POST['to_date'] ) && ! empty( $_POST['to_date'] ) ) { + $to_date = sanitize_text_field( $_POST['to_date'] ); + + $args['date_query']['before'] = $to_date; + $args['date_query']['inclusive'] = true; + } + + if ( ! empty( $_POST['search'] ) ) { + + if ( isset( $args['date_query'] ) ) { + unset( $args['date_query'] ); } + + $args['s'] = sanitize_text_field( $_POST['search'] ); + } + + $posts = new WP_query( $args ); + + foreach ( $posts->posts as $post ) { $date = $post->post_date; - $humanTime = human_time_diff ( strtotime ( $post->post_date_gmt ) ); + $humanTime = human_time_diff( strtotime( $post->post_date_gmt ) ); // if this PHP system support humanTime, than use it - if (! empty ( $humanTime )) { + if ( ! empty( $humanTime ) ) { /* Translators: where %s indicates the relative time from now */ - $date = sprintf ( _x ( '%s ago', 'A relative time as in "five days ago"', Postman::TEXT_DOMAIN ), $humanTime ); + $date = sprintf( _x( '%s ago', 'A relative time as in "five days ago"', Postman::TEXT_DOMAIN ), $humanTime ); } - $flattenedPost = array ( + $flattenedPost = array( // the post title must be escaped as they are displayed in the HTML output - 'title' => esc_html ( $post->post_title ), + 'title' => esc_html( $post->post_title ), // the post status must be escaped as they are displayed in the HTML output - 'status' => ($post->post_excerpt != null ? esc_html ( $post->post_excerpt ) : __ ( 'Sent', Postman::TEXT_DOMAIN )), + 'status' => ($post->post_excerpt != null ? esc_html( $post->post_excerpt ) : __( 'Sent', Postman::TEXT_DOMAIN )), 'date' => $date, - 'ID' => $post->ID + 'ID' => $post->ID, ); - array_push ( $data, $flattenedPost ); + array_push( $data, $flattenedPost ); } - + /** * This checks for sorting input and sorts the data in our array accordingly. * @@ -350,14 +364,13 @@ class PostmanEmailLogView extends WP_List_Table { * to a custom query. The returned data will be pre-sorted, and this array * sorting technique would be unnecessary. */ - function usort_reorder($a, $b) { - $orderby = (! empty ( $_REQUEST ['orderby'] )) ? $_REQUEST ['orderby'] : 'title'; // If no sort, default to title - $order = (! empty ( $_REQUEST ['order'] )) ? $_REQUEST ['order'] : 'asc'; // If no order, default to asc - $result = strcmp ( $a [$orderby], $b [$orderby] ); // Determine sort order + function usort_reorder( $a, $b ) { + $orderby = ( ! empty( $_REQUEST ['orderby'] )) ? $_REQUEST ['orderby'] : 'title'; // If no sort, default to title + $order = ( ! empty( $_REQUEST ['order'] )) ? $_REQUEST ['order'] : 'asc'; // If no order, default to asc + $result = strcmp( $a [ $orderby ], $b [ $orderby ] ); // Determine sort order return ($order === 'asc') ? $result : - $result; // Send final sort direction to usort } // usort($data, 'usort_reorder'); - /** * ********************************************************************* * --------------------------------------------------------------------- @@ -372,15 +385,15 @@ class PostmanEmailLogView extends WP_List_Table { * --------------------------------------------------------------------- * ******************************************************************** */ - + /** * REQUIRED for pagination. * Let's figure out what page the user is currently * looking at. We'll need this later, so you should always include it in * your own package classes. */ - $current_page = $this->get_pagenum (); - + $current_page = $this->get_pagenum(); + /** * REQUIRED for pagination. * Let's check how many items are in our data array. @@ -388,31 +401,31 @@ class PostmanEmailLogView extends WP_List_Table { * without filtering. We'll need this later, so you should always include it * in your own package classes. */ - $total_items = count ( $data ); - + $total_items = count( $data ); + /** * The WP_List_Table class does not handle pagination for us, so we need * to ensure that the data is trimmed to only the current page. * We can use * array_slice() to */ - $data = array_slice ( $data, (($current_page - 1) * $per_page), $per_page ); - + $data = array_slice( $data, (($current_page - 1) * $per_page), $per_page ); + /** * REQUIRED. * Now we can add our *sorted* data to the items property, where * it can be used by the rest of the class. */ $this->items = $data; - + /** * REQUIRED. * We also have to register our pagination options & calculations. */ - $this->set_pagination_args ( array ( + $this->set_pagination_args( array( 'total_items' => $total_items, // WE have to calculate the total number of items 'per_page' => $per_page, // WE have to determine how many items to show on a page - 'total_pages' => ceil ( $total_items / $per_page ) + 'total_pages' => ceil( $total_items / $per_page ), ) ); // WE have to calculate the total number of pages } } diff --git a/Postman/Postman-Mail/Zend-1.12.10/Validate/Hostname.php b/Postman/Postman-Mail/Zend-1.12.10/Validate/Hostname.php index 3b1e8b3..937f9bd 100644 --- a/Postman/Postman-Mail/Zend-1.12.10/Validate/Hostname.php +++ b/Postman/Postman-Mail/Zend-1.12.10/Validate/Hostname.php @@ -23,12 +23,10 @@ * @see Postman_Zend_Validate_Abstract */ // require_once 'Zend/Validate/Abstract.php'; - /** * @see Postman_Zend_Validate_Ip */ // require_once 'Zend/Validate/Ip.php'; - /** * Please note there are two standalone test scripts for testing IDN characters due to problems * with file encoding. @@ -46,1618 +44,2316 @@ */ class Postman_Zend_Validate_Hostname extends Postman_Zend_Validate_Abstract { - const CANNOT_DECODE_PUNYCODE = 'hostnameCannotDecodePunycode'; - const INVALID = 'hostnameInvalid'; - const INVALID_DASH = 'hostnameDashCharacter'; - const INVALID_HOSTNAME = 'hostnameInvalidHostname'; - const INVALID_HOSTNAME_SCHEMA = 'hostnameInvalidHostnameSchema'; - const INVALID_LOCAL_NAME = 'hostnameInvalidLocalName'; - const INVALID_URI = 'hostnameInvalidUri'; - const IP_ADDRESS_NOT_ALLOWED = 'hostnameIpAddressNotAllowed'; - const LOCAL_NAME_NOT_ALLOWED = 'hostnameLocalNameNotAllowed'; - const UNDECIPHERABLE_TLD = 'hostnameUndecipherableTld'; - const UNKNOWN_TLD = 'hostnameUnknownTld'; - - /** - * @var array - */ - protected $_messageTemplates = array( - self::CANNOT_DECODE_PUNYCODE => "'%value%' appears to be a DNS hostname but the given punycode notation cannot be decoded", - self::INVALID => "Invalid type given. String expected", - self::INVALID_DASH => "'%value%' appears to be a DNS hostname but contains a dash in an invalid position", - self::INVALID_HOSTNAME => "'%value%' does not match the expected structure for a DNS hostname", - self::INVALID_HOSTNAME_SCHEMA => "'%value%' appears to be a DNS hostname but cannot match against hostname schema for TLD '%tld%'", - self::INVALID_LOCAL_NAME => "'%value%' does not appear to be a valid local network name", - self::INVALID_URI => "'%value%' does not appear to be a valid URI hostname", - self::IP_ADDRESS_NOT_ALLOWED => "'%value%' appears to be an IP address, but IP addresses are not allowed", - self::LOCAL_NAME_NOT_ALLOWED => "'%value%' appears to be a local network name but local network names are not allowed", - self::UNDECIPHERABLE_TLD => "'%value%' appears to be a DNS hostname but cannot extract TLD part", - self::UNKNOWN_TLD => "'%value%' appears to be a DNS hostname but cannot match TLD against known list", - ); - - /** - * @var array - */ - protected $_messageVariables = array( - 'tld' => '_tld' - ); - - /** - * Allows Internet domain names (e.g., example.com) - */ - const ALLOW_DNS = 1; - - /** - * Allows IP addresses - */ - const ALLOW_IP = 2; - - /** - * Allows local network names (e.g., localhost, www.localdomain) - */ - const ALLOW_LOCAL = 4; - - /** - * Allows all types of hostnames - */ - const ALLOW_URI = 8; - - /** - * Allows all types of hostnames - */ - const ALLOW_ALL = 15; - - /** - * Array of valid top-level-domains - * - * Version 2014112800, Last Updated Fri Nov 28 07:07:01 2014 UTC - * - * @see http://data.iana.org/TLD/tlds-alpha-by-domain.txt List of all TLDs by domain - * @see http://www.iana.org/domains/root/db/ Official list of supported TLDs - * @var array - */ - protected $_validTlds = array( - 'abogado', - 'ac', - 'academy', - 'accountants', - 'active', - 'actor', - 'ad', - 'ae', - 'aero', - 'af', - 'ag', - 'agency', - 'ai', - 'airforce', - 'al', - 'allfinanz', - 'alsace', - 'am', - 'an', - 'android', - 'ao', - 'aq', - 'ar', - 'archi', - 'army', - 'arpa', - 'as', - 'asia', - 'associates', - 'at', - 'attorney', - 'au', - 'auction', - 'audio', - 'autos', - 'aw', - 'ax', - 'axa', - 'az', - 'ba', - 'band', - 'bar', - 'bargains', - 'bayern', - 'bb', - 'bd', - 'be', - 'beer', - 'berlin', - 'best', - 'bf', - 'bg', - 'bh', - 'bi', - 'bid', - 'bike', - 'bio', - 'biz', - 'bj', - 'black', - 'blackfriday', - 'bloomberg', - 'blue', - 'bm', - 'bmw', - 'bn', - 'bnpparibas', - 'bo', - 'boo', - 'boutique', - 'br', - 'brussels', - 'bs', - 'bt', - 'budapest', - 'build', - 'builders', - 'business', - 'buzz', - 'bv', - 'bw', - 'by', - 'bz', - 'bzh', - 'ca', - 'cab', - 'cal', - 'camera', - 'camp', - 'cancerresearch', - 'capetown', - 'capital', - 'caravan', - 'cards', - 'care', - 'career', - 'careers', - 'casa', - 'cash', - 'cat', - 'catering', - 'cc', - 'cd', - 'center', - 'ceo', - 'cern', - 'cf', - 'cg', - 'ch', - 'channel', - 'cheap', - 'christmas', - 'chrome', - 'church', - 'ci', - 'citic', - 'city', - 'ck', - 'cl', - 'claims', - 'cleaning', - 'click', - 'clinic', - 'clothing', - 'club', - 'cm', - 'cn', - 'co', - 'coach', - 'codes', - 'coffee', - 'college', - 'cologne', - 'com', - 'community', - 'company', - 'computer', - 'condos', - 'construction', - 'consulting', - 'contractors', - 'cooking', - 'cool', - 'coop', - 'country', - 'cr', - 'credit', - 'creditcard', - 'cricket', - 'crs', - 'cruises', - 'cu', - 'cuisinella', - 'cv', - 'cw', - 'cx', - 'cy', - 'cymru', - 'cz', - 'dad', - 'dance', - 'dating', - 'day', - 'de', - 'deals', - 'degree', - 'delivery', - 'democrat', - 'dental', - 'dentist', - 'desi', - 'diamonds', - 'diet', - 'digital', - 'direct', - 'directory', - 'discount', - 'dj', - 'dk', - 'dm', - 'dnp', - 'do', - 'domains', - 'durban', - 'dvag', - 'dz', - 'eat', - 'ec', - 'edu', - 'education', - 'ee', - 'eg', - 'email', - 'emerck', - 'energy', - 'engineer', - 'engineering', - 'enterprises', - 'equipment', - 'er', - 'es', - 'esq', - 'estate', - 'et', - 'eu', - 'eus', - 'events', - 'everbank', - 'exchange', - 'expert', - 'exposed', - 'fail', - 'farm', - 'feedback', - 'fi', - 'finance', - 'financial', - 'firmdale', - 'fish', - 'fishing', - 'fitness', - 'fj', - 'fk', - 'flights', - 'florist', - 'flsmidth', - 'fly', - 'fm', - 'fo', - 'foo', - 'forsale', - 'foundation', - 'fr', - 'frl', - 'frogans', - 'fund', - 'furniture', - 'futbol', - 'ga', - 'gal', - 'gallery', - 'gb', - 'gbiz', - 'gd', - 'ge', - 'gent', - 'gf', - 'gg', - 'gh', - 'gi', - 'gift', - 'gifts', - 'gives', - 'gl', - 'glass', - 'gle', - 'global', - 'globo', - 'gm', - 'gmail', - 'gmo', - 'gmx', - 'gn', - 'google', - 'gop', - 'gov', - 'gp', - 'gq', - 'gr', - 'graphics', - 'gratis', - 'green', - 'gripe', - 'gs', - 'gt', - 'gu', - 'guide', - 'guitars', - 'guru', - 'gw', - 'gy', - 'hamburg', - 'haus', - 'healthcare', - 'help', - 'here', - 'hiphop', - 'hiv', - 'hk', - 'hm', - 'hn', - 'holdings', - 'holiday', - 'homes', - 'horse', - 'host', - 'hosting', - 'house', - 'how', - 'hr', - 'ht', - 'hu', - 'ibm', - 'id', - 'ie', - 'il', - 'im', - 'immo', - 'immobilien', - 'in', - 'industries', - 'info', - 'ing', - 'ink', - 'institute', - 'insure', - 'int', - 'international', - 'investments', - 'io', - 'iq', - 'ir', - 'is', - 'it', - 'je', - 'jetzt', - 'jm', - 'jo', - 'jobs', - 'joburg', - 'jp', - 'juegos', - 'kaufen', - 'ke', - 'kg', - 'kh', - 'ki', - 'kim', - 'kitchen', - 'kiwi', - 'km', - 'kn', - 'koeln', - 'kp', - 'kr', - 'krd', - 'kred', - 'kw', - 'ky', - 'kz', - 'la', - 'lacaixa', - 'land', - 'lawyer', - 'lb', - 'lc', - 'lds', - 'lease', - 'legal', - 'lgbt', - 'li', - 'life', - 'lighting', - 'limited', - 'limo', - 'link', - 'lk', - 'loans', - 'london', - 'lotto', - 'lr', - 'ls', - 'lt', - 'ltda', - 'lu', - 'luxe', - 'luxury', - 'lv', - 'ly', - 'ma', - 'madrid', - 'maison', - 'management', - 'mango', - 'market', - 'marketing', - 'mc', - 'md', - 'me', - 'media', - 'meet', - 'melbourne', - 'meme', - 'memorial', - 'menu', - 'mg', - 'mh', - 'miami', - 'mil', - 'mini', - 'mk', - 'ml', - 'mm', - 'mn', - 'mo', - 'mobi', - 'moda', - 'moe', - 'monash', - 'money', - 'mormon', - 'mortgage', - 'moscow', - 'motorcycles', - 'mov', - 'mp', - 'mq', - 'mr', - 'ms', - 'mt', - 'mu', - 'museum', - 'mv', - 'mw', - 'mx', - 'my', - 'mz', - 'na', - 'nagoya', - 'name', - 'navy', - 'nc', - 'ne', - 'net', - 'network', - 'neustar', - 'new', - 'nexus', - 'nf', - 'ng', - 'ngo', - 'nhk', - 'ni', - 'ninja', - 'nl', - 'no', - 'np', - 'nr', - 'nra', - 'nrw', - 'nu', - 'nyc', - 'nz', - 'okinawa', - 'om', - 'ong', - 'onl', - 'ooo', - 'org', - 'organic', - 'otsuka', - 'ovh', - 'pa', - 'paris', - 'partners', - 'parts', - 'party', - 'pe', - 'pf', - 'pg', - 'ph', - 'pharmacy', - 'photo', - 'photography', - 'photos', - 'physio', - 'pics', - 'pictures', - 'pink', - 'pizza', - 'pk', - 'pl', - 'place', - 'plumbing', - 'pm', - 'pn', - 'pohl', - 'poker', - 'post', - 'pr', - 'praxi', - 'press', - 'pro', - 'prod', - 'productions', - 'prof', - 'properties', - 'property', - 'ps', - 'pt', - 'pub', - 'pw', - 'py', - 'qa', - 'qpon', - 'quebec', - 're', - 'realtor', - 'recipes', - 'red', - 'rehab', - 'reise', - 'reisen', - 'reit', - 'ren', - 'rentals', - 'repair', - 'report', - 'republican', - 'rest', - 'restaurant', - 'reviews', - 'rich', - 'rio', - 'rip', - 'ro', - 'rocks', - 'rodeo', - 'rs', - 'rsvp', - 'ru', - 'ruhr', - 'rw', - 'ryukyu', - 'sa', - 'saarland', - 'sarl', - 'sb', - 'sc', - 'sca', - 'scb', - 'schmidt', - 'schule', - 'science', - 'scot', - 'sd', - 'se', - 'services', - 'sexy', - 'sg', - 'sh', - 'shiksha', - 'shoes', - 'si', - 'singles', - 'sj', - 'sk', - 'sl', - 'sm', - 'sn', - 'so', - 'social', - 'software', - 'sohu', - 'solar', - 'solutions', - 'soy', - 'space', - 'spiegel', - 'sr', - 'st', - 'su', - 'supplies', - 'supply', - 'support', - 'surf', - 'surgery', - 'suzuki', - 'sv', - 'sx', - 'sy', - 'sydney', - 'systems', - 'sz', - 'taipei', - 'tatar', - 'tattoo', - 'tax', - 'tc', - 'td', - 'technology', - 'tel', - 'tf', - 'tg', - 'th', - 'tienda', - 'tips', - 'tirol', - 'tj', - 'tk', - 'tl', - 'tm', - 'tn', - 'to', - 'today', - 'tokyo', - 'tools', - 'top', - 'town', - 'toys', - 'tp', - 'tr', - 'trade', - 'training', - 'travel', - 'tt', - 'tui', - 'tv', - 'tw', - 'tz', - 'ua', - 'ug', - 'uk', - 'university', - 'uno', - 'uol', - 'us', - 'uy', - 'uz', - 'va', - 'vacations', - 'vc', - 've', - 'vegas', - 'ventures', - 'versicherung', - 'vet', - 'vg', - 'vi', - 'viajes', - 'villas', - 'vision', - 'vlaanderen', - 'vn', - 'vodka', - 'vote', - 'voting', - 'voto', - 'voyage', - 'vu', - 'wales', - 'wang', - 'watch', - 'webcam', - 'website', - 'wed', - 'wedding', - 'wf', - 'whoswho', - 'wien', - 'wiki', - 'williamhill', - 'wme', - 'work', - 'works', - 'world', - 'ws', - 'wtc', - 'wtf', - 'xn--1qqw23a', - 'xn--3bst00m', - 'xn--3ds443g', - 'xn--3e0b707e', - 'xn--45brj9c', - 'xn--45q11c', - 'xn--4gbrim', - 'xn--55qw42g', - 'xn--55qx5d', - 'xn--6frz82g', - 'xn--6qq986b3xl', - 'xn--80adxhks', - 'xn--80ao21a', - 'xn--80asehdb', - 'xn--80aswg', - 'xn--90a3ac', - 'xn--c1avg', - 'xn--cg4bki', - 'xn--clchc0ea0b2g2a9gcd', - 'xn--czr694b', - 'xn--czru2d', - 'xn--d1acj3b', - 'xn--d1alf', - 'xn--fiq228c5hs', - 'xn--fiq64b', - 'xn--fiqs8s', - 'xn--fiqz9s', - 'xn--flw351e', - 'xn--fpcrj9c3d', - 'xn--fzc2c9e2c', - 'xn--gecrj9c', - 'xn--h2brj9c', - 'xn--i1b6b1a6a2e', - 'xn--io0a7i', - 'xn--j1amh', - 'xn--j6w193g', - 'xn--kprw13d', - 'xn--kpry57d', - 'xn--kput3i', - 'xn--l1acc', - 'xn--lgbbat1ad8j', - 'xn--mgb9awbf', - 'xn--mgba3a4f16a', - 'xn--mgbaam7a8h', - 'xn--mgbab2bd', - 'xn--mgbayh7gpa', - 'xn--mgbbh1a71e', - 'xn--mgbc0a9azcg', - 'xn--mgberp4a5d4ar', - 'xn--mgbx4cd0ab', - 'xn--ngbc5azd', - 'xn--node', - 'xn--nqv7f', - 'xn--nqv7fs00ema', - 'xn--o3cw4h', - 'xn--ogbpf8fl', - 'xn--p1acf', - 'xn--p1ai', - 'xn--pgbs0dh', - 'xn--q9jyb4c', - 'xn--qcka1pmc', - 'xn--rhqv96g', - 'xn--s9brj9c', - 'xn--ses554g', - 'xn--unup4y', - 'xn--vermgensberater-ctb', - 'xn--vermgensberatung-pwb', - 'xn--vhquv', - 'xn--wgbh1c', - 'xn--wgbl6a', - 'xn--xhq521b', - 'xn--xkc2al3hye2a', - 'xn--xkc2dl3a5ee0h', - 'xn--yfro4i67o', - 'xn--ygbi2ammx', - 'xn--zfr164b', - 'xxx', - 'xyz', - 'yachts', - 'yandex', - 'ye', - 'yoga', - 'yokohama', - 'youtube', - 'yt', - 'za', - 'zip', - 'zm', - 'zone', - 'zw', - '测试', - 'परीक्षा', - '佛山', - '集团', - '在线', - '한국', - 'ভারত', - '八卦', - 'موقع', - 'বাংলা', - '公益', - '公司', - '移动', - '我爱你', - 'москва', - 'испытание', - 'қаз', - 'онлайн', - 'сайт', - 'срб', - 'бел', - '테스트', - 'орг', - '삼성', - 'சிங்கப்பூர்', - '商标', - '商城', - 'дети', - 'мкд', - 'טעסט', - '中文网', - '中信', - '中国', - '中國', - '谷歌', - 'భారత్', - 'ලංකා', - '測試', - 'ભારત', - 'भारत', - 'آزمایشی', - 'பரிட்சை', - 'संगठन', - '网络', - 'укр', - '香港', - 'δοκιμή', - 'إختبار', - '台湾', - '台灣', - '手机', - 'мон', - 'الجزائر', - 'عمان', - 'ایران', - 'امارات', - 'بازار', - 'پاکستان', - 'الاردن', - 'بھارت', - 'المغرب', - 'السعودية', - 'سودان', - 'عراق', - 'مليسيا', - 'شبكة', - 'გე', - '机构', - '组织机构', - 'ไทย', - 'سورية', - 'рус', - 'рф', - 'تونس', - 'みんな', - 'グーグル', - '世界', - 'ਭਾਰਤ', - '网址', - '游戏', - 'vermögensberater', - 'vermögensberatung', - '企业', - 'مصر', - 'قطر', - '广东', - 'இலங்கை', - 'இந்தியா', - 'հայ', - '新加坡', - 'فلسطين', - 'テスト', - '政务', - ); - - /** - * @var string - */ - protected $_tld; - - /** - * Array for valid Idns - * @see http://www.iana.org/domains/idn-tables/ Official list of supported IDN Chars - * (.AC) Ascension Island http://www.nic.ac/pdf/AC-IDN-Policy.pdf - * (.AR) Argentinia http://www.nic.ar/faqidn.html - * (.AS) American Samoa http://www.nic.as/idn/chars.cfm - * (.AT) Austria http://www.nic.at/en/service/technical_information/idn/charset_converter/ - * (.BIZ) International http://www.iana.org/domains/idn-tables/ - * (.BR) Brazil http://registro.br/faq/faq6.html - * (.BV) Bouvett Island http://www.norid.no/domeneregistrering/idn/idn_nyetegn.en.html - * (.CA) Canada http://www.iana.org/domains/idn-tables/tables/ca_fr_1.0.html - * (.CAT) Catalan http://www.iana.org/domains/idn-tables/tables/cat_ca_1.0.html - * (.CH) Switzerland https://nic.switch.ch/reg/ocView.action?res=EF6GW2JBPVTG67DLNIQXU234MN6SC33JNQQGI7L6#anhang1 - * (.CL) Chile http://www.iana.org/domains/idn-tables/tables/cl_latn_1.0.html - * (.COM) International http://www.verisign.com/information-services/naming-services/internationalized-domain-names/index.html - * (.DE) Germany http://www.denic.de/en/domains/idns/liste.html - * (.DK) Danmark http://www.dk-hostmaster.dk/index.php?id=151 - * (.ES) Spain https://www.nic.es/media/2008-05/1210147705287.pdf - * (.FI) Finland http://www.ficora.fi/en/index/palvelut/fiverkkotunnukset/aakkostenkaytto.html - * (.GR) Greece https://grweb.ics.forth.gr/CharacterTable1_en.jsp - * (.HU) Hungary http://www.domain.hu/domain/English/szabalyzat/szabalyzat.html - * (.INFO) International http://www.nic.info/info/idn - * (.IO) British Indian Ocean Territory http://www.nic.io/IO-IDN-Policy.pdf - * (.IR) Iran http://www.nic.ir/Allowable_Characters_dot-iran - * (.IS) Iceland http://www.isnic.is/domain/rules.php - * (.KR) Korea http://www.iana.org/domains/idn-tables/tables/kr_ko-kr_1.0.html - * (.LI) Liechtenstein https://nic.switch.ch/reg/ocView.action?res=EF6GW2JBPVTG67DLNIQXU234MN6SC33JNQQGI7L6#anhang1 - * (.LT) Lithuania http://www.domreg.lt/static/doc/public/idn_symbols-en.pdf - * (.MD) Moldova http://www.register.md/ - * (.MUSEUM) International http://www.iana.org/domains/idn-tables/tables/museum_latn_1.0.html - * (.NET) International http://www.verisign.com/information-services/naming-services/internationalized-domain-names/index.html - * (.NO) Norway http://www.norid.no/domeneregistrering/idn/idn_nyetegn.en.html - * (.NU) Niue http://www.worldnames.net/ - * (.ORG) International http://www.pir.org/index.php?db=content/FAQs&tbl=FAQs_Registrant&id=2 - * (.PE) Peru https://www.nic.pe/nuevas_politicas_faq_2.php - * (.PL) Poland http://www.dns.pl/IDN/allowed_character_sets.pdf - * (.PR) Puerto Rico http://www.nic.pr/idn_rules.asp - * (.PT) Portugal https://online.dns.pt/dns_2008/do?com=DS;8216320233;111;+PAGE(4000058)+K-CAT-CODIGO(C.125)+RCNT(100); - * (.RU) Russia http://www.iana.org/domains/idn-tables/tables/ru_ru-ru_1.0.html - * (.RS) Serbia http://www.iana.org/domains/idn-tables/tables/rs_sr-rs_1.0.pdf - * (.SA) Saudi Arabia http://www.iana.org/domains/idn-tables/tables/sa_ar_1.0.html - * (.SE) Sweden http://www.iis.se/english/IDN_campaignsite.shtml?lang=en - * (.SH) Saint Helena http://www.nic.sh/SH-IDN-Policy.pdf - * (.SJ) Svalbard and Jan Mayen http://www.norid.no/domeneregistrering/idn/idn_nyetegn.en.html - * (.TH) Thailand http://www.iana.org/domains/idn-tables/tables/th_th-th_1.0.html - * (.TM) Turkmenistan http://www.nic.tm/TM-IDN-Policy.pdf - * (.TR) Turkey https://www.nic.tr/index.php - * (.UA) Ukraine http://www.iana.org/domains/idn-tables/tables/ua_cyrl_1.2.html - * (.VE) Venice http://www.iana.org/domains/idn-tables/tables/ve_es_1.0.html - * (.VN) Vietnam http://www.vnnic.vn/english/5-6-300-2-2-04-20071115.htm#1.%20Introduction - * - * @var array - */ - protected $_validIdns = array( - 'AC' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿāăąćĉċčďđēėęěĝġģĥħīįĵķĺļľŀłńņňŋőœŕŗřśŝşšţťŧūŭůűųŵŷźżž]{1,63}$/iu'), - 'AR' => array(1 => '/^[\x{002d}0-9a-zà-ãç-êìíñ-õü]{1,63}$/iu'), - 'AS' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿāăąćĉċčďđēĕėęěĝğġģĥħĩīĭįıĵķĸĺļľłńņňŋōŏőœŕŗřśŝşšţťŧũūŭůűųŵŷźż]{1,63}$/iu'), - 'AT' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿœšž]{1,63}$/iu'), - 'BIZ' => 'Hostname/Biz.php', - 'BR' => array(1 => '/^[\x{002d}0-9a-zà-ãçéíó-õúü]{1,63}$/iu'), - 'BV' => array(1 => '/^[\x{002d}0-9a-zàáä-éêñ-ôöøüčđńŋšŧž]{1,63}$/iu'), - 'CA' => array(1 => '/^[\x{002d}0-9a-zàâæçéèêëîïôœùûüÿ\x{00E0}\x{00E2}\x{00E7}\x{00E8}\x{00E9}\x{00EA}\x{00EB}\x{00EE}\x{00EF}\x{00F4}\x{00F9}\x{00FB}\x{00FC}\x{00E6}\x{0153}\x{00FF}]{1,63}$/iu'), - 'CAT' => array(1 => '/^[\x{002d}0-9a-z·àç-éíïòóúü]{1,63}$/iu'), - 'CH' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿœ]{1,63}$/iu'), - 'CL' => array(1 => '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu'), - 'CN' => 'Hostname/Cn.php', - 'COM' => 'Hostname/Com.php', - 'DE' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿăąāćĉčċďđĕěėęēğĝġģĥħĭĩįīıĵķĺľļłńňņŋŏőōœĸŕřŗśŝšşťţŧŭůűũųūŵŷźžż]{1,63}$/iu'), - 'DK' => array(1 => '/^[\x{002d}0-9a-zäéöüæøå]{1,63}$/iu'), - 'ES' => array(1 => '/^[\x{002d}0-9a-zàáçèéíïñòóúü·]{1,63}$/iu'), - 'EU' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿ]{1,63}$/iu', - 2 => '/^[\x{002d}0-9a-zāăąćĉċčďđēĕėęěĝğġģĥħĩīĭįıĵķĺļľŀłńņňʼnŋōŏőœŕŗřśŝšťŧũūŭůűųŵŷźżž]{1,63}$/iu', - 3 => '/^[\x{002d}0-9a-zșț]{1,63}$/iu', - 4 => '/^[\x{002d}0-9a-zΐάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύώ]{1,63}$/iu', - 5 => '/^[\x{002d}0-9a-zабвгдежзийклмнопрстуфхцчшщъыьэюя]{1,63}$/iu', - 6 => '/^[\x{002d}0-9a-zἀ-ἇἐ-ἕἠ-ἧἰ-ἷὀ-ὅὐ-ὗὠ-ὧὰ-ὼώᾀ-ᾇᾐ-ᾗᾠ-ᾧᾰ-ᾴᾶᾷῂῃῄῆῇῐ-ῒΐῖῗῠ-ῧῲῳῴῶῷ]{1,63}$/iu'), - 'FI' => array(1 => '/^[\x{002d}0-9a-zäåö]{1,63}$/iu'), - 'GR' => array(1 => '/^[\x{002d}0-9a-zΆΈΉΊΌΎ-ΡΣ-ώἀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙὛὝὟ-ώᾀ-ᾴᾶ-ᾼῂῃῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲῳῴῶ-ῼ]{1,63}$/iu'), - 'HK' => 'Hostname/Cn.php', - 'HU' => array(1 => '/^[\x{002d}0-9a-záéíóöúüőű]{1,63}$/iu'), - 'IL' => array(1 => '/^[\x{002d}0-9\x{05D0}-\x{05EA}]{1,63}$/iu', - 2 => '/^[\x{002d}0-9a-z]{1,63}$/i'), - 'INFO'=> array(1 => '/^[\x{002d}0-9a-zäåæéöøü]{1,63}$/iu', - 2 => '/^[\x{002d}0-9a-záéíóöúüőű]{1,63}$/iu', - 3 => '/^[\x{002d}0-9a-záæéíðóöúýþ]{1,63}$/iu', - 4 => '/^[\x{AC00}-\x{D7A3}]{1,17}$/iu', - 5 => '/^[\x{002d}0-9a-zāčēģīķļņōŗšūž]{1,63}$/iu', - 6 => '/^[\x{002d}0-9a-ząčėęįšūųž]{1,63}$/iu', - 7 => '/^[\x{002d}0-9a-zóąćęłńśźż]{1,63}$/iu', - 8 => '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu'), - 'IO' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿăąāćĉčċďđĕěėęēğĝġģĥħĭĩįīıĵķĺľļłńňņŋŏőōœĸŕřŗśŝšşťţŧŭůűũųūŵŷźžż]{1,63}$/iu'), - 'IS' => array(1 => '/^[\x{002d}0-9a-záéýúíóþæöð]{1,63}$/iu'), - 'IT' => array(1 => '/^[\x{002d}0-9a-zàâäèéêëìîïòôöùûüæœçÿß-]{1,63}$/iu'), - 'JP' => 'Hostname/Jp.php', - 'KR' => array(1 => '/^[\x{AC00}-\x{D7A3}]{1,17}$/iu'), - 'LI' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿœ]{1,63}$/iu'), - 'LT' => array(1 => '/^[\x{002d}0-9ąčęėįšųūž]{1,63}$/iu'), - 'MD' => array(1 => '/^[\x{002d}0-9ăâîşţ]{1,63}$/iu'), - 'MUSEUM' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿāăąćċčďđēėęěğġģħīįıķĺļľłńņňŋōőœŕŗřśşšţťŧūůűųŵŷźżžǎǐǒǔ\x{01E5}\x{01E7}\x{01E9}\x{01EF}ə\x{0292}ẁẃẅỳ]{1,63}$/iu'), - 'NET' => 'Hostname/Com.php', - 'NO' => array(1 => '/^[\x{002d}0-9a-zàáä-éêñ-ôöøüčđńŋšŧž]{1,63}$/iu'), - 'NU' => 'Hostname/Com.php', - 'ORG' => array(1 => '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu', - 2 => '/^[\x{002d}0-9a-zóąćęłńśźż]{1,63}$/iu', - 3 => '/^[\x{002d}0-9a-záäåæéëíðóöøúüýþ]{1,63}$/iu', - 4 => '/^[\x{002d}0-9a-záéíóöúüőű]{1,63}$/iu', - 5 => '/^[\x{002d}0-9a-ząčėęįšūųž]{1,63}$/iu', - 6 => '/^[\x{AC00}-\x{D7A3}]{1,17}$/iu', - 7 => '/^[\x{002d}0-9a-zāčēģīķļņōŗšūž]{1,63}$/iu'), - 'PE' => array(1 => '/^[\x{002d}0-9a-zñáéíóúü]{1,63}$/iu'), - 'PL' => array(1 => '/^[\x{002d}0-9a-zāčēģīķļņōŗšūž]{1,63}$/iu', - 2 => '/^[\x{002d}а-ик-ш\x{0450}ѓѕјљњќџ]{1,63}$/iu', - 3 => '/^[\x{002d}0-9a-zâîăşţ]{1,63}$/iu', - 4 => '/^[\x{002d}0-9а-яё\x{04C2}]{1,63}$/iu', - 5 => '/^[\x{002d}0-9a-zàáâèéêìíîòóôùúûċġħż]{1,63}$/iu', - 6 => '/^[\x{002d}0-9a-zàäåæéêòóôöøü]{1,63}$/iu', - 7 => '/^[\x{002d}0-9a-zóąćęłńśźż]{1,63}$/iu', - 8 => '/^[\x{002d}0-9a-zàáâãçéêíòóôõúü]{1,63}$/iu', - 9 => '/^[\x{002d}0-9a-zâîăşţ]{1,63}$/iu', - 10=> '/^[\x{002d}0-9a-záäéíóôúýčďĺľňŕšťž]{1,63}$/iu', - 11=> '/^[\x{002d}0-9a-zçë]{1,63}$/iu', - 12=> '/^[\x{002d}0-9а-ик-шђјљњћџ]{1,63}$/iu', - 13=> '/^[\x{002d}0-9a-zćčđšž]{1,63}$/iu', - 14=> '/^[\x{002d}0-9a-zâçöûüğış]{1,63}$/iu', - 15=> '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu', - 16=> '/^[\x{002d}0-9a-zäõöüšž]{1,63}$/iu', - 17=> '/^[\x{002d}0-9a-zĉĝĥĵŝŭ]{1,63}$/iu', - 18=> '/^[\x{002d}0-9a-zâäéëîô]{1,63}$/iu', - 19=> '/^[\x{002d}0-9a-zàáâäåæçèéêëìíîïðñòôöøùúûüýćčłńřśš]{1,63}$/iu', - 20=> '/^[\x{002d}0-9a-zäåæõöøüšž]{1,63}$/iu', - 21=> '/^[\x{002d}0-9a-zàáçèéìíòóùú]{1,63}$/iu', - 22=> '/^[\x{002d}0-9a-zàáéíóöúüőű]{1,63}$/iu', - 23=> '/^[\x{002d}0-9ΐά-ώ]{1,63}$/iu', - 24=> '/^[\x{002d}0-9a-zàáâåæçèéêëðóôöøüþœ]{1,63}$/iu', - 25=> '/^[\x{002d}0-9a-záäéíóöúüýčďěňřšťůž]{1,63}$/iu', - 26=> '/^[\x{002d}0-9a-z·àçèéíïòóúü]{1,63}$/iu', - 27=> '/^[\x{002d}0-9а-ъьюя\x{0450}\x{045D}]{1,63}$/iu', - 28=> '/^[\x{002d}0-9а-яёіў]{1,63}$/iu', - 29=> '/^[\x{002d}0-9a-ząčėęįšūųž]{1,63}$/iu', - 30=> '/^[\x{002d}0-9a-záäåæéëíðóöøúüýþ]{1,63}$/iu', - 31=> '/^[\x{002d}0-9a-zàâæçèéêëîïñôùûüÿœ]{1,63}$/iu', - 32=> '/^[\x{002d}0-9а-щъыьэюяёєіїґ]{1,63}$/iu', - 33=> '/^[\x{002d}0-9א-ת]{1,63}$/iu'), - 'PR' => array(1 => '/^[\x{002d}0-9a-záéíóúñäëïüöâêîôûàèùæçœãõ]{1,63}$/iu'), - 'PT' => array(1 => '/^[\x{002d}0-9a-záàâãçéêíóôõú]{1,63}$/iu'), - 'RS' => array(1 => '/^[\x{002D}\x{0030}-\x{0039}\x{0061}-\x{007A}\x{0107}\x{010D}\x{0111}\x{0161}\x{017E}]{1,63}$/iu)'), - 'RU' => array(1 => '/^[\x{002d}0-9а-яё]{1,63}$/iu'), - 'SA' => array(1 => '/^[\x{002d}.0-9\x{0621}-\x{063A}\x{0641}-\x{064A}\x{0660}-\x{0669}]{1,63}$/iu'), - 'SE' => array(1 => '/^[\x{002d}0-9a-zäåéöü]{1,63}$/iu'), - 'SH' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿăąāćĉčċďđĕěėęēğĝġģĥħĭĩįīıĵķĺľļłńňņŋŏőōœĸŕřŗśŝšşťţŧŭůűũųūŵŷźžż]{1,63}$/iu'), - 'SI' => array( - 1 => '/^[\x{002d}0-9a-zà-öø-ÿ]{1,63}$/iu', - 2 => '/^[\x{002d}0-9a-zāăąćĉċčďđēĕėęěĝğġģĥħĩīĭįıĵķĺļľŀłńņňʼnŋōŏőœŕŗřśŝšťŧũūŭůűųŵŷźżž]{1,63}$/iu', - 3 => '/^[\x{002d}0-9a-zșț]{1,63}$/iu'), - 'SJ' => array(1 => '/^[\x{002d}0-9a-zàáä-éêñ-ôöøüčđńŋšŧž]{1,63}$/iu'), - 'TH' => array(1 => '/^[\x{002d}0-9a-z\x{0E01}-\x{0E3A}\x{0E40}-\x{0E4D}\x{0E50}-\x{0E59}]{1,63}$/iu'), - 'TM' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿāăąćĉċčďđēėęěĝġģĥħīįĵķĺļľŀłńņňŋőœŕŗřśŝşšţťŧūŭůűųŵŷźżž]{1,63}$/iu'), - 'TW' => 'Hostname/Cn.php', - 'TR' => array(1 => '/^[\x{002d}0-9a-zğıüşöç]{1,63}$/iu'), - 'UA' => array(1 => '/^[\x{002d}0-9a-zабвгдежзийклмнопрстуфхцчшщъыьэюяѐёђѓєѕіїјљњћќѝўџґӂʼ]{1,63}$/iu'), - 'VE' => array(1 => '/^[\x{002d}0-9a-záéíóúüñ]{1,63}$/iu'), - 'VN' => array(1 => '/^[ÀÁÂÃÈÉÊÌÍÒÓÔÕÙÚÝàáâãèéêìíòóôõùúýĂăĐđĨĩŨũƠơƯư\x{1EA0}-\x{1EF9}]{1,63}$/iu'), - 'мон' => array(1 => '/^[\x{002d}0-9\x{0430}-\x{044F}]{1,63}$/iu'), - 'срб' => array(1 => '/^[\x{002d}0-9а-ик-шђјљњћџ]{1,63}$/iu'), - 'сайт' => array(1 => '/^[\x{002d}0-9а-яёіїѝйўґг]{1,63}$/iu'), - 'онлайн' => array(1 => '/^[\x{002d}0-9а-яёіїѝйўґг]{1,63}$/iu'), - '中国' => 'Hostname/Cn.php', - '中國' => 'Hostname/Cn.php', - 'ලංකා' => array(1 => '/^[\x{0d80}-\x{0dff}]{1,63}$/iu'), - '香港' => 'Hostname/Cn.php', - '台湾' => 'Hostname/Cn.php', - '台灣' => 'Hostname/Cn.php', - 'امارات' => array(1 => '/^[\x{0621}-\x{0624}\x{0626}-\x{063A}\x{0641}\x{0642}\x{0644}-\x{0648}\x{067E}\x{0686}\x{0698}\x{06A9}\x{06AF}\x{06CC}\x{06F0}-\x{06F9}]{1,30}$/iu'), - 'الاردن' => array(1 => '/^[\x{0621}-\x{0624}\x{0626}-\x{063A}\x{0641}\x{0642}\x{0644}-\x{0648}\x{067E}\x{0686}\x{0698}\x{06A9}\x{06AF}\x{06CC}\x{06F0}-\x{06F9}]{1,30}$/iu'), - 'السعودية' => array(1 => '/^[\x{0621}-\x{0624}\x{0626}-\x{063A}\x{0641}\x{0642}\x{0644}-\x{0648}\x{067E}\x{0686}\x{0698}\x{06A9}\x{06AF}\x{06CC}\x{06F0}-\x{06F9}]{1,30}$/iu'), - 'ไทย' => array(1 => '/^[\x{002d}0-9a-z\x{0E01}-\x{0E3A}\x{0E40}-\x{0E4D}\x{0E50}-\x{0E59}]{1,63}$/iu'), - 'рф' => array(1 => '/^[\x{002d}0-9а-яё]{1,63}$/iu'), - 'تونس' => array(1 => '/^[\x{0621}-\x{0624}\x{0626}-\x{063A}\x{0641}\x{0642}\x{0644}-\x{0648}\x{067E}\x{0686}\x{0698}\x{06A9}\x{06AF}\x{06CC}\x{06F0}-\x{06F9}]{1,30}$/iu'), - 'مصر' => array(1 => '/^[\x{0621}-\x{0624}\x{0626}-\x{063A}\x{0641}\x{0642}\x{0644}-\x{0648}\x{067E}\x{0686}\x{0698}\x{06A9}\x{06AF}\x{06CC}\x{06F0}-\x{06F9}]{1,30}$/iu'), - 'இலங்கை' => array(1 => '/^[\x{0b80}-\x{0bff}]{1,63}$/iu'), - 'فلسطين' => array(1 => '/^[\x{0621}-\x{0624}\x{0626}-\x{063A}\x{0641}\x{0642}\x{0644}-\x{0648}\x{067E}\x{0686}\x{0698}\x{06A9}\x{06AF}\x{06CC}\x{06F0}-\x{06F9}]{1,30}$/iu'), - 'شبكة' => array(1 => '/^[\x{0621}-\x{0624}\x{0626}-\x{063A}\x{0641}\x{0642}\x{0644}-\x{0648}\x{067E}\x{0686}\x{0698}\x{06A9}\x{06AF}\x{06CC}\x{06F0}-\x{06F9}]{1,30}$/iu'), - ); - - protected $_idnLength = array( - 'BIZ' => array(5 => 17, 11 => 15, 12 => 20), - 'CN' => array(1 => 20), - 'COM' => array(3 => 17, 5 => 20), - 'HK' => array(1 => 15), - 'INFO'=> array(4 => 17), - 'KR' => array(1 => 17), - 'NET' => array(3 => 17, 5 => 20), - 'ORG' => array(6 => 17), - 'TW' => array(1 => 20), - 'ایران' => array(1 => 30), - '中国' => array(1 => 20), - '公司' => array(1 => 20), - '网络' => array(1 => 20), - ); - - protected $_options = array( - 'allow' => self::ALLOW_DNS, - 'idn' => true, - 'tld' => true, - 'ip' => null - ); - - /** - * Sets validator options - * - * @see http://www.iana.org/cctld/specifications-policies-cctlds-01apr02.htm Technical Specifications for ccTLDs - * @param array $options Validator options - */ - public function __construct($options = array()) - { - if ($options instanceof Postman_Zend_Config) { - $options = $options->toArray(); - } else if (!is_array($options)) { - $options = func_get_args(); - $temp['allow'] = array_shift($options); - if (!empty($options)) { - $temp['idn'] = array_shift($options); - } - - if (!empty($options)) { - $temp['tld'] = array_shift($options); - } - - if (!empty($options)) { - $temp['ip'] = array_shift($options); - } - - $options = $temp; - } - - $options += $this->_options; - $this->setOptions($options); - } - - /** - * Returns all set options - * - * @return array - */ - public function getOptions() - { - return $this->_options; - } - - /** - * Sets the options for this validator - * - * @param array $options - * @return Postman_Zend_Validate_Hostname - */ - public function setOptions($options) - { - if (array_key_exists('allow', $options)) { - $this->setAllow($options['allow']); - } - - if (array_key_exists('idn', $options)) { - $this->setValidateIdn($options['idn']); - } - - if (array_key_exists('tld', $options)) { - $this->setValidateTld($options['tld']); - } - - if (array_key_exists('ip', $options)) { - $this->setIpValidator($options['ip']); - } - - return $this; - } - - /** - * Returns the set ip validator - * - * @return Postman_Zend_Validate_Ip - */ - public function getIpValidator() - { - return $this->_options['ip']; - } - - /** - * @param Postman_Zend_Validate_Ip $ipValidator OPTIONAL - * @return Postman_Zend_Validate_Hostname - */ - public function setIpValidator(Postman_Zend_Validate_Ip $ipValidator = null) - { - if ($ipValidator === null) { - $ipValidator = new Postman_Zend_Validate_Ip(); - } - - $this->_options['ip'] = $ipValidator; - return $this; - } - - /** - * Returns the allow option - * - * @return integer - */ - public function getAllow() - { - return $this->_options['allow']; - } - - /** - * Sets the allow option - * - * @param integer $allow - * @return Postman_Zend_Validate_Hostname Provides a fluent interface - */ - public function setAllow($allow) - { - $this->_options['allow'] = $allow; - return $this; - } - - /** - * Returns the set idn option - * - * @return boolean - */ - public function getValidateIdn() - { - return $this->_options['idn']; - } - - /** - * Set whether IDN domains are validated - * - * This only applies when DNS hostnames are validated - * - * @param boolean $allowed Set allowed to true to validate IDNs, and false to not validate them - * @return $this - */ - public function setValidateIdn ($allowed) - { - $this->_options['idn'] = (bool) $allowed; - return $this; - } - - /** - * Returns the set tld option - * - * @return boolean - */ - public function getValidateTld() - { - return $this->_options['tld']; - } - - /** - * Set whether the TLD element of a hostname is validated - * - * This only applies when DNS hostnames are validated - * - * @param boolean $allowed Set allowed to true to validate TLDs, and false to not validate them - * @return $this - */ - public function setValidateTld ($allowed) - { - $this->_options['tld'] = (bool) $allowed; - return $this; - } - - /** - * Defined by Postman_Zend_Validate_Interface - * - * Returns true if and only if the $value is a valid hostname with respect to the current allow option - * - * @param string $value - * @throws Postman_Zend_Validate_Exception if a fatal error occurs for validation process - * @return boolean - */ - public function isValid($value) - { - if (!is_string($value)) { - $this->_error(self::INVALID); - return false; - } - - $this->_setValue($value); - // Check input against IP address schema - if (preg_match('/^[0-9a-f:.]*$/i', $value) && - $this->_options['ip']->setTranslator($this->getTranslator())->isValid($value)) { - if (!($this->_options['allow'] & self::ALLOW_IP)) { - $this->_error(self::IP_ADDRESS_NOT_ALLOWED); - return false; - } else { - return true; - } - } - - // RFC3986 3.2.2 states: - // - // The rightmost domain label of a fully qualified domain name - // in DNS may be followed by a single "." and should be if it is - // necessary to distinguish between the complete domain name and - // some local domain. - // - // (see ZF-6363) - - // Local hostnames are allowed to be partitial (ending '.') - if ($this->_options['allow'] & self::ALLOW_LOCAL) { - if (substr($value, -1) === '.') { - $value = substr($value, 0, -1); - if (substr($value, -1) === '.') { - // Empty hostnames (ending '..') are not allowed - $this->_error(self::INVALID_LOCAL_NAME); - return false; - } - } - } - - $domainParts = explode('.', $value); - - // Prevent partitial IP V4 adresses (ending '.') - if ((count($domainParts) == 4) && preg_match('/^[0-9.a-e:.]*$/i', $value) && - $this->_options['ip']->setTranslator($this->getTranslator())->isValid($value)) { - $this->_error(self::INVALID_LOCAL_NAME); - } - - // Check input against DNS hostname schema - if ((count($domainParts) > 1) && (strlen($value) >= 4) && (strlen($value) <= 254)) { - $status = false; - - $origenc = PHP_VERSION_ID < 50600 - ? iconv_get_encoding('internal_encoding') - : ini_get('default_charset'); - if (PHP_VERSION_ID < 50600) { - iconv_set_encoding('internal_encoding', 'UTF-8'); - } else { - // jason was here - @ini_set('default_charset', 'UTF-8'); - } - do { - // First check TLD - $matches = array(); - if (preg_match('/([^.]{2,63})$/iu', end($domainParts), $matches) - || (array_key_exists(end($domainParts), $this->_validIdns))) { - reset($domainParts); - - // Hostname characters are: *(label dot)(label dot label); max 254 chars - // label: id-prefix [*ldh{61} id-prefix]; max 63 chars - // id-prefix: alpha / digit - // ldh: alpha / digit / dash - - // Match TLD against known list - $this->_tld = $matches[1]; - if ($this->_options['tld']) { - if (!in_array(strtolower($this->_tld), $this->_validTlds) - && !in_array($this->_tld, $this->_validTlds)) { - $this->_error(self::UNKNOWN_TLD); - $status = false; - break; - } - // We have already validated that the TLD is fine. We don't want it to go through the below - // checks as new UTF-8 TLDs will incorrectly fail if there is no IDN regex for it. - array_pop($domainParts); - } - - /** - * Match against IDN hostnames - * Note: Keep label regex short to avoid issues with long patterns when matching IDN hostnames - * @see Postman_Zend_Validate_Hostname_Interface - */ - $regexChars = array(0 => '/^[a-z0-9\x2d]{1,63}$/i'); - if ($this->_options['idn'] && isset($this->_validIdns[strtoupper($this->_tld)])) { - if (is_string($this->_validIdns[strtoupper($this->_tld)])) { - $regexChars += include($this->_validIdns[strtoupper($this->_tld)]); - } else { - $regexChars += $this->_validIdns[strtoupper($this->_tld)]; - } - } - - // Check each hostname part - $check = 0; - foreach ($domainParts as $domainPart) { - // If some domain part is empty (i.e. zend..com), it's invalid - if (empty($domainPart)) { - $this->_error(self::INVALID_HOSTNAME); - return false; - } - - // Decode Punycode domainnames to IDN - if (strpos($domainPart, 'xn--') === 0) { - $domainPart = $this->decodePunycode(substr($domainPart, 4)); - if ($domainPart === false) { - return false; - } - } - - // Check dash (-) does not start, end or appear in 3rd and 4th positions - if ((strpos($domainPart, '-') === 0) - || ((strlen($domainPart) > 2) && (strpos($domainPart, '-', 2) == 2) && (strpos($domainPart, '-', 3) == 3)) - || (strpos($domainPart, '-') === (strlen($domainPart) - 1))) { - $this->_error(self::INVALID_DASH); - $status = false; - break 2; - } - - // Check each domain part - $checked = false; - foreach($regexChars as $regexKey => $regexChar) { - $status = preg_match($regexChar, $domainPart); - if ($status > 0) { - $length = 63; - if (array_key_exists(strtoupper($this->_tld), $this->_idnLength) - && (array_key_exists($regexKey, $this->_idnLength[strtoupper($this->_tld)]))) { - $length = $this->_idnLength[strtoupper($this->_tld)]; - } - - if (iconv_strlen($domainPart, 'UTF-8') > $length) { - $this->_error(self::INVALID_HOSTNAME); - } else { - $checked = true; - break; - } - } - } - - if ($checked) { - ++$check; - } - } - - // If one of the labels doesn't match, the hostname is invalid - if ($check !== count($domainParts)) { - $this->_error(self::INVALID_HOSTNAME_SCHEMA); - $status = false; - } - } else { - // Hostname not long enough - $this->_error(self::UNDECIPHERABLE_TLD); - $status = false; - } - } while (false); - - if (PHP_VERSION_ID < 50600) { - iconv_set_encoding('internal_encoding', $origenc); - } else { - // jason was here - @ini_set('default_charset', $origenc); - } - // If the input passes as an Internet domain name, and domain names are allowed, then the hostname - // passes validation - if ($status && ($this->_options['allow'] & self::ALLOW_DNS)) { - return true; - } - } else if ($this->_options['allow'] & self::ALLOW_DNS) { - $this->_error(self::INVALID_HOSTNAME); - } - - // Check for URI Syntax (RFC3986) - if ($this->_options['allow'] & self::ALLOW_URI) { - if (preg_match("/^([a-zA-Z0-9-._~!$&\'()*+,;=]|%[[:xdigit:]]{2}){1,254}$/i", $value)) { - return true; - } else { - $this->_error(self::INVALID_URI); - } - } - - // Check input against local network name schema; last chance to pass validation - $regexLocal = '/^(([a-zA-Z0-9\x2d]{1,63}\x2e)*[a-zA-Z0-9\x2d]{1,63}[\x2e]{0,1}){1,254}$/'; - $status = @preg_match($regexLocal, $value); - - // If the input passes as a local network name, and local network names are allowed, then the - // hostname passes validation - $allowLocal = $this->_options['allow'] & self::ALLOW_LOCAL; - if ($status && $allowLocal) { - return true; - } - - // If the input does not pass as a local network name, add a message - if (!$status) { - $this->_error(self::INVALID_LOCAL_NAME); - } - - // If local network names are not allowed, add a message - if ($status && !$allowLocal) { - $this->_error(self::LOCAL_NAME_NOT_ALLOWED); - } - - return false; - } - - /** - * Decodes a punycode encoded string to it's original utf8 string - * In case of a decoding failure the original string is returned - * - * @param string $encoded Punycode encoded string to decode - * @return string - */ - protected function decodePunycode($encoded) - { - if (!preg_match('/^[a-z0-9-]+$/i', $encoded)) { - // no punycode encoded string - $this->_error(self::CANNOT_DECODE_PUNYCODE); - return false; - } - - $decoded = array(); - $separator = strrpos($encoded, '-'); - if ($separator > 0) { - for ($x = 0; $x < $separator; ++$x) { - // prepare decoding matrix - $decoded[] = ord($encoded[$x]); - } - } - - $lengthd = count($decoded); - $lengthe = strlen($encoded); - - // decoding - $init = true; - $base = 72; - $index = 0; - $char = 0x80; - - for ($indexe = ($separator) ? ($separator + 1) : 0; $indexe < $lengthe; ++$lengthd) { - for ($old_index = $index, $pos = 1, $key = 36; 1 ; $key += 36) { - $hex = ord($encoded[$indexe++]); - $digit = ($hex - 48 < 10) ? $hex - 22 - : (($hex - 65 < 26) ? $hex - 65 - : (($hex - 97 < 26) ? $hex - 97 - : 36)); - - $index += $digit * $pos; - $tag = ($key <= $base) ? 1 : (($key >= $base + 26) ? 26 : ($key - $base)); - if ($digit < $tag) { - break; - } - - $pos = (int) ($pos * (36 - $tag)); - } - - $delta = intval($init ? (($index - $old_index) / 700) : (($index - $old_index) / 2)); - $delta += intval($delta / ($lengthd + 1)); - for ($key = 0; $delta > 910 / 2; $key += 36) { - $delta = intval($delta / 35); - } - - $base = intval($key + 36 * $delta / ($delta + 38)); - $init = false; - $char += (int) ($index / ($lengthd + 1)); - $index %= ($lengthd + 1); - if ($lengthd > 0) { - for ($i = $lengthd; $i > $index; $i--) { - $decoded[$i] = $decoded[($i - 1)]; - } - } - - $decoded[$index++] = $char; - } - - // convert decoded ucs4 to utf8 string - foreach ($decoded as $key => $value) { - if ($value < 128) { - $decoded[$key] = chr($value); - } elseif ($value < (1 << 11)) { - $decoded[$key] = chr(192 + ($value >> 6)); - $decoded[$key] .= chr(128 + ($value & 63)); - } elseif ($value < (1 << 16)) { - $decoded[$key] = chr(224 + ($value >> 12)); - $decoded[$key] .= chr(128 + (($value >> 6) & 63)); - $decoded[$key] .= chr(128 + ($value & 63)); - } elseif ($value < (1 << 21)) { - $decoded[$key] = chr(240 + ($value >> 18)); - $decoded[$key] .= chr(128 + (($value >> 12) & 63)); - $decoded[$key] .= chr(128 + (($value >> 6) & 63)); - $decoded[$key] .= chr(128 + ($value & 63)); - } else { - $this->_error(self::CANNOT_DECODE_PUNYCODE); - return false; - } - } - - return implode($decoded); - } + const CANNOT_DECODE_PUNYCODE = 'hostnameCannotDecodePunycode'; + const INVALID = 'hostnameInvalid'; + const INVALID_DASH = 'hostnameDashCharacter'; + const INVALID_HOSTNAME = 'hostnameInvalidHostname'; + const INVALID_HOSTNAME_SCHEMA = 'hostnameInvalidHostnameSchema'; + const INVALID_LOCAL_NAME = 'hostnameInvalidLocalName'; + const INVALID_URI = 'hostnameInvalidUri'; + const IP_ADDRESS_NOT_ALLOWED = 'hostnameIpAddressNotAllowed'; + const LOCAL_NAME_NOT_ALLOWED = 'hostnameLocalNameNotAllowed'; + const UNDECIPHERABLE_TLD = 'hostnameUndecipherableTld'; + const UNKNOWN_TLD = 'hostnameUnknownTld'; + + /** + * @var array + */ + protected $_messageTemplates = array( + self::CANNOT_DECODE_PUNYCODE => "'%value%' appears to be a DNS hostname but the given punycode notation cannot be decoded", + self::INVALID => 'Invalid type given. String expected', + self::INVALID_DASH => "'%value%' appears to be a DNS hostname but contains a dash in an invalid position", + self::INVALID_HOSTNAME => "'%value%' does not match the expected structure for a DNS hostname", + self::INVALID_HOSTNAME_SCHEMA => "'%value%' appears to be a DNS hostname but cannot match against hostname schema for TLD '%tld%'", + self::INVALID_LOCAL_NAME => "'%value%' does not appear to be a valid local network name", + self::INVALID_URI => "'%value%' does not appear to be a valid URI hostname", + self::IP_ADDRESS_NOT_ALLOWED => "'%value%' appears to be an IP address, but IP addresses are not allowed", + self::LOCAL_NAME_NOT_ALLOWED => "'%value%' appears to be a local network name but local network names are not allowed", + self::UNDECIPHERABLE_TLD => "'%value%' appears to be a DNS hostname but cannot extract TLD part", + self::UNKNOWN_TLD => "'%value%' appears to be a DNS hostname but cannot match TLD against known list", + ); + + /** + * @var array + */ + protected $_messageVariables = array( + 'tld' => '_tld', + ); + + /** + * Allows Internet domain names (e.g., example.com) + */ + const ALLOW_DNS = 1; + + /** + * Allows IP addresses + */ + const ALLOW_IP = 2; + + /** + * Allows local network names (e.g., localhost, www.localdomain) + */ + const ALLOW_LOCAL = 4; + + /** + * Allows all types of hostnames + */ + const ALLOW_URI = 8; + + /** + * Allows all types of hostnames + */ + const ALLOW_ALL = 15; + + /** + * Array of valid top-level-domains + * + * Version 2014112800, Last Updated Fri Nov 28 07:07:01 2014 UTC + * + * @see http://data.iana.org/TLD/tlds-alpha-by-domain.txt List of all TLDs by domain + * @see http://www.iana.org/domains/root/db/ Official list of supported TLDs + * @var array + */ + protected $_validTlds = array( + 'aaa', + 'aarp', + 'abarth', + 'abb', + 'abbott', + 'abbvie', + 'abc', + 'able', + 'abogado', + 'abudhabi', + 'ac', + 'academy', + 'accenture', + 'accountant', + 'accountants', + 'aco', + 'active', + 'actor', + 'ad', + 'adac', + 'ads', + 'adult', + 'ae', + 'aeg', + 'aero', + 'aetna', + 'af', + 'afamilycompany', + 'afl', + 'africa', + 'ag', + 'agakhan', + 'agency', + 'ai', + 'aig', + 'aigo', + 'airbus', + 'airforce', + 'airtel', + 'akdn', + 'al', + 'alfaromeo', + 'alibaba', + 'alipay', + 'allfinanz', + 'allstate', + 'ally', + 'alsace', + 'alstom', + 'am', + 'americanexpress', + 'americanfamily', + 'amex', + 'amfam', + 'amica', + 'amsterdam', + 'analytics', + 'android', + 'anquan', + 'anz', + 'ao', + 'aol', + 'apartments', + 'app', + 'apple', + 'aq', + 'aquarelle', + 'ar', + 'arab', + 'aramco', + 'archi', + 'army', + 'arpa', + 'art', + 'arte', + 'as', + 'asda', + 'asia', + 'associates', + 'at', + 'athleta', + 'attorney', + 'au', + 'auction', + 'audi', + 'audible', + 'audio', + 'auspost', + 'author', + 'auto', + 'autos', + 'avianca', + 'aw', + 'aws', + 'ax', + 'axa', + 'az', + 'azure', + 'ba', + 'baby', + 'baidu', + 'banamex', + 'bananarepublic', + 'band', + 'bank', + 'bar', + 'barcelona', + 'barclaycard', + 'barclays', + 'barefoot', + 'bargains', + 'baseball', + 'basketball', + 'bauhaus', + 'bayern', + 'bb', + 'bbc', + 'bbt', + 'bbva', + 'bcg', + 'bcn', + 'bd', + 'be', + 'beats', + 'beauty', + 'beer', + 'bentley', + 'berlin', + 'best', + 'bestbuy', + 'bet', + 'bf', + 'bg', + 'bh', + 'bharti', + 'bi', + 'bible', + 'bid', + 'bike', + 'bing', + 'bingo', + 'bio', + 'biz', + 'bj', + 'black', + 'blackfriday', + 'blanco', + 'blockbuster', + 'blog', + 'bloomberg', + 'blue', + 'bm', + 'bms', + 'bmw', + 'bn', + 'bnl', + 'bnpparibas', + 'bo', + 'boats', + 'boehringer', + 'bofa', + 'bom', + 'bond', + 'boo', + 'book', + 'booking', + 'boots', + 'bosch', + 'bostik', + 'boston', + 'bot', + 'boutique', + 'box', + 'br', + 'bradesco', + 'bridgestone', + 'broadway', + 'broker', + 'brother', + 'brussels', + 'bs', + 'bt', + 'budapest', + 'bugatti', + 'build', + 'builders', + 'business', + 'buy', + 'buzz', + 'bv', + 'bw', + 'by', + 'bz', + 'bzh', + 'ca', + 'cab', + 'cafe', + 'cal', + 'call', + 'calvinklein', + 'cam', + 'camera', + 'camp', + 'cancerresearch', + 'canon', + 'capetown', + 'capital', + 'capitalone', + 'car', + 'caravan', + 'cards', + 'care', + 'career', + 'careers', + 'cars', + 'cartier', + 'casa', + 'case', + 'caseih', + 'cash', + 'casino', + 'cat', + 'catering', + 'catholic', + 'cba', + 'cbn', + 'cbre', + 'cbs', + 'cc', + 'cd', + 'ceb', + 'center', + 'ceo', + 'cern', + 'cf', + 'cfa', + 'cfd', + 'cg', + 'ch', + 'chanel', + 'channel', + 'chase', + 'chat', + 'cheap', + 'chintai', + 'chloe', + 'christmas', + 'chrome', + 'chrysler', + 'church', + 'ci', + 'cipriani', + 'circle', + 'cisco', + 'citadel', + 'citi', + 'citic', + 'city', + 'cityeats', + 'ck', + 'cl', + 'claims', + 'cleaning', + 'click', + 'clinic', + 'clinique', + 'clothing', + 'cloud', + 'club', + 'clubmed', + 'cm', + 'cn', + 'co', + 'coach', + 'codes', + 'coffee', + 'college', + 'cologne', + 'com', + 'comcast', + 'commbank', + 'community', + 'company', + 'compare', + 'computer', + 'comsec', + 'condos', + 'construction', + 'consulting', + 'contact', + 'contractors', + 'cooking', + 'cookingchannel', + 'cool', + 'coop', + 'corsica', + 'country', + 'coupon', + 'coupons', + 'courses', + 'cr', + 'credit', + 'creditcard', + 'creditunion', + 'cricket', + 'crown', + 'crs', + 'cruise', + 'cruises', + 'csc', + 'cu', + 'cuisinella', + 'cv', + 'cw', + 'cx', + 'cy', + 'cymru', + 'cyou', + 'cz', + 'dabur', + 'dad', + 'dance', + 'data', + 'date', + 'dating', + 'datsun', + 'day', + 'dclk', + 'dds', + 'de', + 'deal', + 'dealer', + 'deals', + 'degree', + 'delivery', + 'dell', + 'deloitte', + 'delta', + 'democrat', + 'dental', + 'dentist', + 'desi', + 'design', + 'dev', + 'dhl', + 'diamonds', + 'diet', + 'digital', + 'direct', + 'directory', + 'discount', + 'discover', + 'dish', + 'diy', + 'dj', + 'dk', + 'dm', + 'dnp', + 'do', + 'docs', + 'doctor', + 'dodge', + 'dog', + 'doha', + 'domains', + 'dot', + 'download', + 'drive', + 'dtv', + 'dubai', + 'duck', + 'dunlop', + 'duns', + 'dupont', + 'durban', + 'dvag', + 'dvr', + 'dz', + 'earth', + 'eat', + 'ec', + 'eco', + 'edeka', + 'edu', + 'education', + 'ee', + 'eg', + 'email', + 'emerck', + 'energy', + 'engineer', + 'engineering', + 'enterprises', + 'epost', + 'epson', + 'equipment', + 'er', + 'ericsson', + 'erni', + 'es', + 'esq', + 'estate', + 'esurance', + 'et', + 'etisalat', + 'eu', + 'eurovision', + 'eus', + 'events', + 'everbank', + 'exchange', + 'expert', + 'exposed', + 'express', + 'extraspace', + 'fage', + 'fail', + 'fairwinds', + 'faith', + 'family', + 'fan', + 'fans', + 'farm', + 'farmers', + 'fashion', + 'fast', + 'fedex', + 'feedback', + 'ferrari', + 'ferrero', + 'fi', + 'fiat', + 'fidelity', + 'fido', + 'film', + 'final', + 'finance', + 'financial', + 'fire', + 'firestone', + 'firmdale', + 'fish', + 'fishing', + 'fit', + 'fitness', + 'fj', + 'fk', + 'flickr', + 'flights', + 'flir', + 'florist', + 'flowers', + 'fly', + 'fm', + 'fo', + 'foo', + 'food', + 'foodnetwork', + 'football', + 'ford', + 'forex', + 'forsale', + 'forum', + 'foundation', + 'fox', + 'fr', + 'free', + 'fresenius', + 'frl', + 'frogans', + 'frontdoor', + 'frontier', + 'ftr', + 'fujitsu', + 'fujixerox', + 'fun', + 'fund', + 'furniture', + 'futbol', + 'fyi', + 'ga', + 'gal', + 'gallery', + 'gallo', + 'gallup', + 'game', + 'games', + 'gap', + 'garden', + 'gb', + 'gbiz', + 'gd', + 'gdn', + 'ge', + 'gea', + 'gent', + 'genting', + 'george', + 'gf', + 'gg', + 'ggee', + 'gh', + 'gi', + 'gift', + 'gifts', + 'gives', + 'giving', + 'gl', + 'glade', + 'glass', + 'gle', + 'global', + 'globo', + 'gm', + 'gmail', + 'gmbh', + 'gmo', + 'gmx', + 'gn', + 'godaddy', + 'gold', + 'goldpoint', + 'golf', + 'goo', + 'goodhands', + 'goodyear', + 'goog', + 'google', + 'gop', + 'got', + 'gov', + 'gp', + 'gq', + 'gr', + 'grainger', + 'graphics', + 'gratis', + 'green', + 'gripe', + 'grocery', + 'group', + 'gs', + 'gt', + 'gu', + 'guardian', + 'gucci', + 'guge', + 'guide', + 'guitars', + 'guru', + 'gw', + 'gy', + 'hair', + 'hamburg', + 'hangout', + 'haus', + 'hbo', + 'hdfc', + 'hdfcbank', + 'health', + 'healthcare', + 'help', + 'helsinki', + 'here', + 'hermes', + 'hgtv', + 'hiphop', + 'hisamitsu', + 'hitachi', + 'hiv', + 'hk', + 'hkt', + 'hm', + 'hn', + 'hockey', + 'holdings', + 'holiday', + 'homedepot', + 'homegoods', + 'homes', + 'homesense', + 'honda', + 'honeywell', + 'horse', + 'hospital', + 'host', + 'hosting', + 'hot', + 'hoteles', + 'hotels', + 'hotmail', + 'house', + 'how', + 'hr', + 'hsbc', + 'ht', + 'htc', + 'hu', + 'hughes', + 'hyatt', + 'hyundai', + 'ibm', + 'icbc', + 'ice', + 'icu', + 'id', + 'ie', + 'ieee', + 'ifm', + 'ikano', + 'il', + 'im', + 'imamat', + 'imdb', + 'immo', + 'immobilien', + 'in', + 'industries', + 'infiniti', + 'info', + 'ing', + 'ink', + 'institute', + 'insurance', + 'insure', + 'int', + 'intel', + 'international', + 'intuit', + 'investments', + 'io', + 'ipiranga', + 'iq', + 'ir', + 'irish', + 'is', + 'iselect', + 'ismaili', + 'ist', + 'istanbul', + 'it', + 'itau', + 'itv', + 'iveco', + 'iwc', + 'jaguar', + 'java', + 'jcb', + 'jcp', + 'je', + 'jeep', + 'jetzt', + 'jewelry', + 'jio', + 'jlc', + 'jll', + 'jm', + 'jmp', + 'jnj', + 'jo', + 'jobs', + 'joburg', + 'jot', + 'joy', + 'jp', + 'jpmorgan', + 'jprs', + 'juegos', + 'juniper', + 'kaufen', + 'kddi', + 'ke', + 'kerryhotels', + 'kerrylogistics', + 'kerryproperties', + 'kfh', + 'kg', + 'kh', + 'ki', + 'kia', + 'kim', + 'kinder', + 'kindle', + 'kitchen', + 'kiwi', + 'km', + 'kn', + 'koeln', + 'komatsu', + 'kosher', + 'kp', + 'kpmg', + 'kpn', + 'kr', + 'krd', + 'kred', + 'kuokgroup', + 'kw', + 'ky', + 'kyoto', + 'kz', + 'la', + 'lacaixa', + 'ladbrokes', + 'lamborghini', + 'lamer', + 'lancaster', + 'lancia', + 'lancome', + 'land', + 'landrover', + 'lanxess', + 'lasalle', + 'lat', + 'latino', + 'latrobe', + 'law', + 'lawyer', + 'lb', + 'lc', + 'lds', + 'lease', + 'leclerc', + 'lefrak', + 'legal', + 'lego', + 'lexus', + 'lgbt', + 'li', + 'liaison', + 'lidl', + 'life', + 'lifeinsurance', + 'lifestyle', + 'lighting', + 'like', + 'lilly', + 'limited', + 'limo', + 'lincoln', + 'linde', + 'link', + 'lipsy', + 'live', + 'living', + 'lixil', + 'lk', + 'loan', + 'loans', + 'locker', + 'locus', + 'loft', + 'lol', + 'london', + 'lotte', + 'lotto', + 'love', + 'lpl', + 'lplfinancial', + 'lr', + 'ls', + 'lt', + 'ltd', + 'ltda', + 'lu', + 'lundbeck', + 'lupin', + 'luxe', + 'luxury', + 'lv', + 'ly', + 'ma', + 'macys', + 'madrid', + 'maif', + 'maison', + 'makeup', + 'man', + 'management', + 'mango', + 'map', + 'market', + 'marketing', + 'markets', + 'marriott', + 'marshalls', + 'maserati', + 'mattel', + 'mba', + 'mc', + 'mcd', + 'mcdonalds', + 'mckinsey', + 'md', + 'me', + 'med', + 'media', + 'meet', + 'melbourne', + 'meme', + 'memorial', + 'men', + 'menu', + 'meo', + 'merckmsd', + 'metlife', + 'mg', + 'mh', + 'miami', + 'microsoft', + 'mil', + 'mini', + 'mint', + 'mit', + 'mitsubishi', + 'mk', + 'ml', + 'mlb', + 'mls', + 'mm', + 'mma', + 'mn', + 'mo', + 'mobi', + 'mobile', + 'mobily', + 'moda', + 'moe', + 'moi', + 'mom', + 'monash', + 'money', + 'monster', + 'montblanc', + 'mopar', + 'mormon', + 'mortgage', + 'moscow', + 'moto', + 'motorcycles', + 'mov', + 'movie', + 'movistar', + 'mp', + 'mq', + 'mr', + 'ms', + 'msd', + 'mt', + 'mtn', + 'mtr', + 'mu', + 'museum', + 'mutual', + 'mv', + 'mw', + 'mx', + 'my', + 'mz', + 'na', + 'nab', + 'nadex', + 'nagoya', + 'name', + 'nationwide', + 'natura', + 'navy', + 'nba', + 'nc', + 'ne', + 'nec', + 'net', + 'netbank', + 'netflix', + 'network', + 'neustar', + 'new', + 'newholland', + 'news', + 'next', + 'nextdirect', + 'nexus', + 'nf', + 'nfl', + 'ng', + 'ngo', + 'nhk', + 'ni', + 'nico', + 'nike', + 'nikon', + 'ninja', + 'nissan', + 'nissay', + 'nl', + 'no', + 'nokia', + 'northwesternmutual', + 'norton', + 'now', + 'nowruz', + 'nowtv', + 'np', + 'nr', + 'nra', + 'nrw', + 'ntt', + 'nu', + 'nyc', + 'nz', + 'obi', + 'observer', + 'off', + 'office', + 'okinawa', + 'olayan', + 'olayangroup', + 'oldnavy', + 'ollo', + 'om', + 'omega', + 'one', + 'ong', + 'onl', + 'online', + 'onyourside', + 'ooo', + 'open', + 'oracle', + 'orange', + 'org', + 'organic', + 'origins', + 'osaka', + 'otsuka', + 'ott', + 'ovh', + 'pa', + 'page', + 'pamperedchef', + 'panasonic', + 'panerai', + 'paris', + 'pars', + 'partners', + 'parts', + 'party', + 'passagens', + 'pay', + 'pccw', + 'pe', + 'pet', + 'pf', + 'pfizer', + 'pg', + 'ph', + 'pharmacy', + 'phd', + 'philips', + 'phone', + 'photo', + 'photography', + 'photos', + 'physio', + 'piaget', + 'pics', + 'pictet', + 'pictures', + 'pid', + 'pin', + 'ping', + 'pink', + 'pioneer', + 'pizza', + 'pk', + 'pl', + 'place', + 'play', + 'playstation', + 'plumbing', + 'plus', + 'pm', + 'pn', + 'pnc', + 'pohl', + 'poker', + 'politie', + 'porn', + 'post', + 'pr', + 'pramerica', + 'praxi', + 'press', + 'prime', + 'pro', + 'prod', + 'productions', + 'prof', + 'progressive', + 'promo', + 'properties', + 'property', + 'protection', + 'pru', + 'prudential', + 'ps', + 'pt', + 'pub', + 'pw', + 'pwc', + 'py', + 'qa', + 'qpon', + 'quebec', + 'quest', + 'qvc', + 'racing', + 'radio', + 'raid', + 're', + 'read', + 'realestate', + 'realtor', + 'realty', + 'recipes', + 'red', + 'redstone', + 'redumbrella', + 'rehab', + 'reise', + 'reisen', + 'reit', + 'reliance', + 'ren', + 'rent', + 'rentals', + 'repair', + 'report', + 'republican', + 'rest', + 'restaurant', + 'review', + 'reviews', + 'rexroth', + 'rich', + 'richardli', + 'ricoh', + 'rightathome', + 'ril', + 'rio', + 'rip', + 'rmit', + 'ro', + 'rocher', + 'rocks', + 'rodeo', + 'rogers', + 'room', + 'rs', + 'rsvp', + 'ru', + 'rugby', + 'ruhr', + 'run', + 'rw', + 'rwe', + 'ryukyu', + 'sa', + 'saarland', + 'safe', + 'safety', + 'sakura', + 'sale', + 'salon', + 'samsclub', + 'samsung', + 'sandvik', + 'sandvikcoromant', + 'sanofi', + 'sap', + 'sapo', + 'sarl', + 'sas', + 'save', + 'saxo', + 'sb', + 'sbi', + 'sbs', + 'sc', + 'sca', + 'scb', + 'schaeffler', + 'schmidt', + 'scholarships', + 'school', + 'schule', + 'schwarz', + 'science', + 'scjohnson', + 'scor', + 'scot', + 'sd', + 'se', + 'search', + 'seat', + 'secure', + 'security', + 'seek', + 'select', + 'sener', + 'services', + 'ses', + 'seven', + 'sew', + 'sex', + 'sexy', + 'sfr', + 'sg', + 'sh', + 'shangrila', + 'sharp', + 'shaw', + 'shell', + 'shia', + 'shiksha', + 'shoes', + 'shop', + 'shopping', + 'shouji', + 'show', + 'showtime', + 'shriram', + 'si', + 'silk', + 'sina', + 'singles', + 'site', + 'sj', + 'sk', + 'ski', + 'skin', + 'sky', + 'skype', + 'sl', + 'sling', + 'sm', + 'smart', + 'smile', + 'sn', + 'sncf', + 'so', + 'soccer', + 'social', + 'softbank', + 'software', + 'sohu', + 'solar', + 'solutions', + 'song', + 'sony', + 'soy', + 'space', + 'spiegel', + 'spot', + 'spreadbetting', + 'sr', + 'srl', + 'srt', + 'st', + 'stada', + 'staples', + 'star', + 'starhub', + 'statebank', + 'statefarm', + 'statoil', + 'stc', + 'stcgroup', + 'stockholm', + 'storage', + 'store', + 'stream', + 'studio', + 'study', + 'style', + 'su', + 'sucks', + 'supplies', + 'supply', + 'support', + 'surf', + 'surgery', + 'suzuki', + 'sv', + 'swatch', + 'swiftcover', + 'swiss', + 'sx', + 'sy', + 'sydney', + 'symantec', + 'systems', + 'sz', + 'tab', + 'taipei', + 'talk', + 'taobao', + 'target', + 'tatamotors', + 'tatar', + 'tattoo', + 'tax', + 'taxi', + 'tc', + 'tci', + 'td', + 'tdk', + 'team', + 'tech', + 'technology', + 'tel', + 'telecity', + 'telefonica', + 'temasek', + 'tennis', + 'teva', + 'tf', + 'tg', + 'th', + 'thd', + 'theater', + 'theatre', + 'tiaa', + 'tickets', + 'tienda', + 'tiffany', + 'tips', + 'tires', + 'tirol', + 'tj', + 'tjmaxx', + 'tjx', + 'tk', + 'tkmaxx', + 'tl', + 'tm', + 'tmall', + 'tn', + 'to', + 'today', + 'tokyo', + 'tools', + 'top', + 'toray', + 'toshiba', + 'total', + 'tours', + 'town', + 'toyota', + 'toys', + 'tr', + 'trade', + 'trading', + 'training', + 'travel', + 'travelchannel', + 'travelers', + 'travelersinsurance', + 'trust', + 'trv', + 'tt', + 'tube', + 'tui', + 'tunes', + 'tushu', + 'tv', + 'tvs', + 'tw', + 'tz', + 'ua', + 'ubank', + 'ubs', + 'uconnect', + 'ug', + 'uk', + 'unicom', + 'university', + 'uno', + 'uol', + 'ups', + 'us', + 'uy', + 'uz', + 'va', + 'vacations', + 'vana', + 'vanguard', + 'vc', + 've', + 'vegas', + 'ventures', + 'verisign', + 'versicherung', + 'vet', + 'vg', + 'vi', + 'viajes', + 'video', + 'vig', + 'viking', + 'villas', + 'vin', + 'vip', + 'virgin', + 'visa', + 'vision', + 'vista', + 'vistaprint', + 'viva', + 'vivo', + 'vlaanderen', + 'vn', + 'vodka', + 'volkswagen', + 'volvo', + 'vote', + 'voting', + 'voto', + 'voyage', + 'vu', + 'vuelos', + 'wales', + 'walmart', + 'walter', + 'wang', + 'wanggou', + 'warman', + 'watch', + 'watches', + 'weather', + 'weatherchannel', + 'webcam', + 'weber', + 'website', + 'wed', + 'wedding', + 'weibo', + 'weir', + 'wf', + 'whoswho', + 'wien', + 'wiki', + 'williamhill', + 'win', + 'windows', + 'wine', + 'winners', + 'wme', + 'wolterskluwer', + 'woodside', + 'work', + 'works', + 'world', + 'wow', + 'ws', + 'wtc', + 'wtf', + 'xbox', + 'xerox', + 'xfinity', + 'xihuan', + 'xin', + 'कॉम', + 'セール', + '佛山', + 'ಭಾರತ', + '慈善', + '集团', + '在线', + '한국', + 'ଭାରତ', + '大众汽车', + '点看', + 'คอม', + 'ভাৰত', + 'ভারত', + '八卦', + 'موقع', + 'বাংলা', + '公益', + '公司', + '香格里拉', + '网站', + '移动', + '我爱你', + 'москва', + 'қаз', + 'католик', + 'онлайн', + 'сайт', + '联通', + 'срб', + 'бг', + 'бел', + 'קום', + '时尚', + '微博', + '淡马锡', + 'ファッション', + 'орг', + 'नेट', + 'ストア', + '삼성', + 'சிங்கப்பூர்', + '商标', + '商店', + '商城', + 'дети', + 'мкд', + 'ею', + 'ポイント', + '新闻', + '工行', + '家電', + 'كوم', + '中文网', + '中信', + '中国', + '中國', + '娱乐', + '谷歌', + 'భారత్', + 'ලංකා', + '電訊盈科', + '购物', + 'クラウド', + 'ભારત', + '通販', + 'भारतम्', + 'भारत', + 'भारोत', + '网店', + 'संगठन', + '餐厅', + '网络', + 'ком', + 'укр', + '香港', + '诺基亚', + '食品', + '飞利浦', + '台湾', + '台灣', + '手表', + '手机', + 'мон', + 'الجزائر', + 'عمان', + 'ارامكو', + 'ایران', + 'العليان', + 'اتصالات', + 'امارات', + 'بازار', + 'پاکستان', + 'الاردن', + 'موبايلي', + 'بارت', + 'بھارت', + 'المغرب', + 'ابوظبي', + 'السعودية', + 'ڀارت', + 'كاثوليك', + 'سودان', + 'همراه', + 'عراق', + 'مليسيا', + '澳門', + '닷컴', + '政府', + 'شبكة', + 'بيتك', + 'عرب', + 'გე', + '机构', + '组织机构', + '健康', + 'ไทย', + 'سورية', + 'рус', + 'рф', + '珠宝', + 'تونس', + '大拿', + 'みんな', + 'グーグル', + 'ελ', + '世界', + '書籍', + 'ഭാരതം', + 'ਭਾਰਤ', + '网址', + '닷넷', + 'コム', + '天主教', + '游戏', + 'vermögensberater', + 'vermögensberatung', + '企业', + '信息', + '嘉里大酒店', + '嘉里', + 'مصر', + 'قطر', + '广东', + 'இலங்கை', + 'இந்தியா', + 'հայ', + '新加坡', + 'فلسطين', + '政务', + 'xperia', + 'xxx', + 'xyz', + 'yachts', + 'yahoo', + 'yamaxun', + 'yandex', + 'ye', + 'yodobashi', + 'yoga', + 'yokohama', + 'you', + 'youtube', + 'yt', + 'yun', + 'za', + 'zappos', + 'zara', + 'zero', + 'zip', + 'zippo', + 'zm', + 'zone', + 'zuerich', + 'zw', + ); + + /** + * @var string + */ + protected $_tld; + + /** + * Array for valid Idns + * + * @see http://www.iana.org/domains/idn-tables/ Official list of supported IDN Chars + * (.AC) Ascension Island http://www.nic.ac/pdf/AC-IDN-Policy.pdf + * (.AR) Argentinia http://www.nic.ar/faqidn.html + * (.AS) American Samoa http://www.nic.as/idn/chars.cfm + * (.AT) Austria http://www.nic.at/en/service/technical_information/idn/charset_converter/ + * (.BIZ) International http://www.iana.org/domains/idn-tables/ + * (.BR) Brazil http://registro.br/faq/faq6.html + * (.BV) Bouvett Island http://www.norid.no/domeneregistrering/idn/idn_nyetegn.en.html + * (.CA) Canada http://www.iana.org/domains/idn-tables/tables/ca_fr_1.0.html + * (.CAT) Catalan http://www.iana.org/domains/idn-tables/tables/cat_ca_1.0.html + * (.CH) Switzerland https://nic.switch.ch/reg/ocView.action?res=EF6GW2JBPVTG67DLNIQXU234MN6SC33JNQQGI7L6#anhang1 + * (.CL) Chile http://www.iana.org/domains/idn-tables/tables/cl_latn_1.0.html + * (.COM) International http://www.verisign.com/information-services/naming-services/internationalized-domain-names/index.html + * (.DE) Germany http://www.denic.de/en/domains/idns/liste.html + * (.DK) Danmark http://www.dk-hostmaster.dk/index.php?id=151 + * (.ES) Spain https://www.nic.es/media/2008-05/1210147705287.pdf + * (.FI) Finland http://www.ficora.fi/en/index/palvelut/fiverkkotunnukset/aakkostenkaytto.html + * (.GR) Greece https://grweb.ics.forth.gr/CharacterTable1_en.jsp + * (.HU) Hungary http://www.domain.hu/domain/English/szabalyzat/szabalyzat.html + * (.INFO) International http://www.nic.info/info/idn + * (.IO) British Indian Ocean Territory http://www.nic.io/IO-IDN-Policy.pdf + * (.IR) Iran http://www.nic.ir/Allowable_Characters_dot-iran + * (.IS) Iceland http://www.isnic.is/domain/rules.php + * (.KR) Korea http://www.iana.org/domains/idn-tables/tables/kr_ko-kr_1.0.html + * (.LI) Liechtenstein https://nic.switch.ch/reg/ocView.action?res=EF6GW2JBPVTG67DLNIQXU234MN6SC33JNQQGI7L6#anhang1 + * (.LT) Lithuania http://www.domreg.lt/static/doc/public/idn_symbols-en.pdf + * (.MD) Moldova http://www.register.md/ + * (.MUSEUM) International http://www.iana.org/domains/idn-tables/tables/museum_latn_1.0.html + * (.NET) International http://www.verisign.com/information-services/naming-services/internationalized-domain-names/index.html + * (.NO) Norway http://www.norid.no/domeneregistrering/idn/idn_nyetegn.en.html + * (.NU) Niue http://www.worldnames.net/ + * (.ORG) International http://www.pir.org/index.php?db=content/FAQs&tbl=FAQs_Registrant&id=2 + * (.PE) Peru https://www.nic.pe/nuevas_politicas_faq_2.php + * (.PL) Poland http://www.dns.pl/IDN/allowed_character_sets.pdf + * (.PR) Puerto Rico http://www.nic.pr/idn_rules.asp + * (.PT) Portugal https://online.dns.pt/dns_2008/do?com=DS;8216320233;111;+PAGE(4000058)+K-CAT-CODIGO(C.125)+RCNT(100); + * (.RU) Russia http://www.iana.org/domains/idn-tables/tables/ru_ru-ru_1.0.html + * (.RS) Serbia http://www.iana.org/domains/idn-tables/tables/rs_sr-rs_1.0.pdf + * (.SA) Saudi Arabia http://www.iana.org/domains/idn-tables/tables/sa_ar_1.0.html + * (.SE) Sweden http://www.iis.se/english/IDN_campaignsite.shtml?lang=en + * (.SH) Saint Helena http://www.nic.sh/SH-IDN-Policy.pdf + * (.SJ) Svalbard and Jan Mayen http://www.norid.no/domeneregistrering/idn/idn_nyetegn.en.html + * (.TH) Thailand http://www.iana.org/domains/idn-tables/tables/th_th-th_1.0.html + * (.TM) Turkmenistan http://www.nic.tm/TM-IDN-Policy.pdf + * (.TR) Turkey https://www.nic.tr/index.php + * (.UA) Ukraine http://www.iana.org/domains/idn-tables/tables/ua_cyrl_1.2.html + * (.VE) Venice http://www.iana.org/domains/idn-tables/tables/ve_es_1.0.html + * (.VN) Vietnam http://www.vnnic.vn/english/5-6-300-2-2-04-20071115.htm#1.%20Introduction + * + * @var array + */ + protected $_validIdns = array( + 'AC' => array( 1 => '/^[\x{002d}0-9a-zà-öø-ÿāăąćĉċčďđēėęěĝġģĥħīįĵķĺļľŀłńņňŋőœŕŗřśŝşšţťŧūŭůűųŵŷźżž]{1,63}$/iu' ), + 'AR' => array( 1 => '/^[\x{002d}0-9a-zà-ãç-êìíñ-õü]{1,63}$/iu' ), + 'AS' => array( 1 => '/^[\x{002d}0-9a-zà-öø-ÿāăąćĉċčďđēĕėęěĝğġģĥħĩīĭįıĵķĸĺļľłńņňŋōŏőœŕŗřśŝşšţťŧũūŭůűųŵŷźż]{1,63}$/iu' ), + 'AT' => array( 1 => '/^[\x{002d}0-9a-zà-öø-ÿœšž]{1,63}$/iu' ), + 'BIZ' => 'Hostname/Biz.php', + 'BR' => array( 1 => '/^[\x{002d}0-9a-zà-ãçéíó-õúü]{1,63}$/iu' ), + 'BV' => array( 1 => '/^[\x{002d}0-9a-zàáä-éêñ-ôöøüčđńŋšŧž]{1,63}$/iu' ), + 'CA' => array( 1 => '/^[\x{002d}0-9a-zàâæçéèêëîïôœùûüÿ\x{00E0}\x{00E2}\x{00E7}\x{00E8}\x{00E9}\x{00EA}\x{00EB}\x{00EE}\x{00EF}\x{00F4}\x{00F9}\x{00FB}\x{00FC}\x{00E6}\x{0153}\x{00FF}]{1,63}$/iu' ), + 'CAT' => array( 1 => '/^[\x{002d}0-9a-z·àç-éíïòóúü]{1,63}$/iu' ), + 'CH' => array( 1 => '/^[\x{002d}0-9a-zà-öø-ÿœ]{1,63}$/iu' ), + 'CL' => array( 1 => '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu' ), + 'CN' => 'Hostname/Cn.php', + 'COM' => 'Hostname/Com.php', + 'DE' => array( 1 => '/^[\x{002d}0-9a-zà-öø-ÿăąāćĉčċďđĕěėęēğĝġģĥħĭĩįīıĵķĺľļłńňņŋŏőōœĸŕřŗśŝšşťţŧŭůűũųūŵŷźžż]{1,63}$/iu' ), + 'DK' => array( 1 => '/^[\x{002d}0-9a-zäéöüæøå]{1,63}$/iu' ), + 'ES' => array( 1 => '/^[\x{002d}0-9a-zàáçèéíïñòóúü·]{1,63}$/iu' ), + 'EU' => array( + 1 => '/^[\x{002d}0-9a-zà-öø-ÿ]{1,63}$/iu', + 2 => '/^[\x{002d}0-9a-zāăąćĉċčďđēĕėęěĝğġģĥħĩīĭįıĵķĺļľŀłńņňʼnŋōŏőœŕŗřśŝšťŧũūŭůűųŵŷźżž]{1,63}$/iu', + 3 => '/^[\x{002d}0-9a-zșț]{1,63}$/iu', + 4 => '/^[\x{002d}0-9a-zΐάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύώ]{1,63}$/iu', + 5 => '/^[\x{002d}0-9a-zабвгдежзийклмнопрстуфхцчшщъыьэюя]{1,63}$/iu', + 6 => '/^[\x{002d}0-9a-zἀ-ἇἐ-ἕἠ-ἧἰ-ἷὀ-ὅὐ-ὗὠ-ὧὰ-ὼώᾀ-ᾇᾐ-ᾗᾠ-ᾧᾰ-ᾴᾶᾷῂῃῄῆῇῐ-ῒΐῖῗῠ-ῧῲῳῴῶῷ]{1,63}$/iu', + ), + 'FI' => array( 1 => '/^[\x{002d}0-9a-zäåö]{1,63}$/iu' ), + 'GR' => array( 1 => '/^[\x{002d}0-9a-zΆΈΉΊΌΎ-ΡΣ-ώἀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙὛὝὟ-ώᾀ-ᾴᾶ-ᾼῂῃῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲῳῴῶ-ῼ]{1,63}$/iu' ), + 'HK' => 'Hostname/Cn.php', + 'HU' => array( 1 => '/^[\x{002d}0-9a-záéíóöúüőű]{1,63}$/iu' ), + 'IL' => array( + 1 => '/^[\x{002d}0-9\x{05D0}-\x{05EA}]{1,63}$/iu', + 2 => '/^[\x{002d}0-9a-z]{1,63}$/i', + ), + 'INFO' => array( + 1 => '/^[\x{002d}0-9a-zäåæéöøü]{1,63}$/iu', + 2 => '/^[\x{002d}0-9a-záéíóöúüőű]{1,63}$/iu', + 3 => '/^[\x{002d}0-9a-záæéíðóöúýþ]{1,63}$/iu', + 4 => '/^[\x{AC00}-\x{D7A3}]{1,17}$/iu', + 5 => '/^[\x{002d}0-9a-zāčēģīķļņōŗšūž]{1,63}$/iu', + 6 => '/^[\x{002d}0-9a-ząčėęįšūųž]{1,63}$/iu', + 7 => '/^[\x{002d}0-9a-zóąćęłńśźż]{1,63}$/iu', + 8 => '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu', + ), + 'IO' => array( 1 => '/^[\x{002d}0-9a-zà-öø-ÿăąāćĉčċďđĕěėęēğĝġģĥħĭĩįīıĵķĺľļłńňņŋŏőōœĸŕřŗśŝšşťţŧŭůűũųūŵŷźžż]{1,63}$/iu' ), + 'IS' => array( 1 => '/^[\x{002d}0-9a-záéýúíóþæöð]{1,63}$/iu' ), + 'IT' => array( 1 => '/^[\x{002d}0-9a-zàâäèéêëìîïòôöùûüæœçÿß-]{1,63}$/iu' ), + 'JP' => 'Hostname/Jp.php', + 'KR' => array( 1 => '/^[\x{AC00}-\x{D7A3}]{1,17}$/iu' ), + 'LI' => array( 1 => '/^[\x{002d}0-9a-zà-öø-ÿœ]{1,63}$/iu' ), + 'LT' => array( 1 => '/^[\x{002d}0-9ąčęėįšųūž]{1,63}$/iu' ), + 'MD' => array( 1 => '/^[\x{002d}0-9ăâîşţ]{1,63}$/iu' ), + 'MUSEUM' => array( 1 => '/^[\x{002d}0-9a-zà-öø-ÿāăąćċčďđēėęěğġģħīįıķĺļľłńņňŋōőœŕŗřśşšţťŧūůűųŵŷźżžǎǐǒǔ\x{01E5}\x{01E7}\x{01E9}\x{01EF}ə\x{0292}ẁẃẅỳ]{1,63}$/iu' ), + 'NET' => 'Hostname/Com.php', + 'NO' => array( 1 => '/^[\x{002d}0-9a-zàáä-éêñ-ôöøüčđńŋšŧž]{1,63}$/iu' ), + 'NU' => 'Hostname/Com.php', + 'ORG' => array( + 1 => '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu', + 2 => '/^[\x{002d}0-9a-zóąćęłńśźż]{1,63}$/iu', + 3 => '/^[\x{002d}0-9a-záäåæéëíðóöøúüýþ]{1,63}$/iu', + 4 => '/^[\x{002d}0-9a-záéíóöúüőű]{1,63}$/iu', + 5 => '/^[\x{002d}0-9a-ząčėęįšūųž]{1,63}$/iu', + 6 => '/^[\x{AC00}-\x{D7A3}]{1,17}$/iu', + 7 => '/^[\x{002d}0-9a-zāčēģīķļņōŗšūž]{1,63}$/iu', + ), + 'PE' => array( 1 => '/^[\x{002d}0-9a-zñáéíóúü]{1,63}$/iu' ), + 'PL' => array( + 1 => '/^[\x{002d}0-9a-zāčēģīķļņōŗšūž]{1,63}$/iu', + 2 => '/^[\x{002d}а-ик-ш\x{0450}ѓѕјљњќџ]{1,63}$/iu', + 3 => '/^[\x{002d}0-9a-zâîăşţ]{1,63}$/iu', + 4 => '/^[\x{002d}0-9а-яё\x{04C2}]{1,63}$/iu', + 5 => '/^[\x{002d}0-9a-zàáâèéêìíîòóôùúûċġħż]{1,63}$/iu', + 6 => '/^[\x{002d}0-9a-zàäåæéêòóôöøü]{1,63}$/iu', + 7 => '/^[\x{002d}0-9a-zóąćęłńśźż]{1,63}$/iu', + 8 => '/^[\x{002d}0-9a-zàáâãçéêíòóôõúü]{1,63}$/iu', + 9 => '/^[\x{002d}0-9a-zâîăşţ]{1,63}$/iu', + 10 => '/^[\x{002d}0-9a-záäéíóôúýčďĺľňŕšťž]{1,63}$/iu', + 11 => '/^[\x{002d}0-9a-zçë]{1,63}$/iu', + 12 => '/^[\x{002d}0-9а-ик-шђјљњћџ]{1,63}$/iu', + 13 => '/^[\x{002d}0-9a-zćčđšž]{1,63}$/iu', + 14 => '/^[\x{002d}0-9a-zâçöûüğış]{1,63}$/iu', + 15 => '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu', + 16 => '/^[\x{002d}0-9a-zäõöüšž]{1,63}$/iu', + 17 => '/^[\x{002d}0-9a-zĉĝĥĵŝŭ]{1,63}$/iu', + 18 => '/^[\x{002d}0-9a-zâäéëîô]{1,63}$/iu', + 19 => '/^[\x{002d}0-9a-zàáâäåæçèéêëìíîïðñòôöøùúûüýćčłńřśš]{1,63}$/iu', + 20 => '/^[\x{002d}0-9a-zäåæõöøüšž]{1,63}$/iu', + 21 => '/^[\x{002d}0-9a-zàáçèéìíòóùú]{1,63}$/iu', + 22 => '/^[\x{002d}0-9a-zàáéíóöúüőű]{1,63}$/iu', + 23 => '/^[\x{002d}0-9ΐά-ώ]{1,63}$/iu', + 24 => '/^[\x{002d}0-9a-zàáâåæçèéêëðóôöøüþœ]{1,63}$/iu', + 25 => '/^[\x{002d}0-9a-záäéíóöúüýčďěňřšťůž]{1,63}$/iu', + 26 => '/^[\x{002d}0-9a-z·àçèéíïòóúü]{1,63}$/iu', + 27 => '/^[\x{002d}0-9а-ъьюя\x{0450}\x{045D}]{1,63}$/iu', + 28 => '/^[\x{002d}0-9а-яёіў]{1,63}$/iu', + 29 => '/^[\x{002d}0-9a-ząčėęįšūųž]{1,63}$/iu', + 30 => '/^[\x{002d}0-9a-záäåæéëíðóöøúüýþ]{1,63}$/iu', + 31 => '/^[\x{002d}0-9a-zàâæçèéêëîïñôùûüÿœ]{1,63}$/iu', + 32 => '/^[\x{002d}0-9а-щъыьэюяёєіїґ]{1,63}$/iu', + 33 => '/^[\x{002d}0-9א-ת]{1,63}$/iu', + ), + 'PR' => array( 1 => '/^[\x{002d}0-9a-záéíóúñäëïüöâêîôûàèùæçœãõ]{1,63}$/iu' ), + 'PT' => array( 1 => '/^[\x{002d}0-9a-záàâãçéêíóôõú]{1,63}$/iu' ), + 'RS' => array( 1 => '/^[\x{002D}\x{0030}-\x{0039}\x{0061}-\x{007A}\x{0107}\x{010D}\x{0111}\x{0161}\x{017E}]{1,63}$/iu)' ), + 'RU' => array( 1 => '/^[\x{002d}0-9а-яё]{1,63}$/iu' ), + 'SA' => array( 1 => '/^[\x{002d}.0-9\x{0621}-\x{063A}\x{0641}-\x{064A}\x{0660}-\x{0669}]{1,63}$/iu' ), + 'SE' => array( 1 => '/^[\x{002d}0-9a-zäåéöü]{1,63}$/iu' ), + 'SH' => array( 1 => '/^[\x{002d}0-9a-zà-öø-ÿăąāćĉčċďđĕěėęēğĝġģĥħĭĩįīıĵķĺľļłńňņŋŏőōœĸŕřŗśŝšşťţŧŭůűũųūŵŷźžż]{1,63}$/iu' ), + 'SI' => array( + 1 => '/^[\x{002d}0-9a-zà-öø-ÿ]{1,63}$/iu', + 2 => '/^[\x{002d}0-9a-zāăąćĉċčďđēĕėęěĝğġģĥħĩīĭįıĵķĺļľŀłńņňʼnŋōŏőœŕŗřśŝšťŧũūŭůűųŵŷźżž]{1,63}$/iu', + 3 => '/^[\x{002d}0-9a-zșț]{1,63}$/iu', + ), + 'SJ' => array( 1 => '/^[\x{002d}0-9a-zàáä-éêñ-ôöøüčđńŋšŧž]{1,63}$/iu' ), + 'TH' => array( 1 => '/^[\x{002d}0-9a-z\x{0E01}-\x{0E3A}\x{0E40}-\x{0E4D}\x{0E50}-\x{0E59}]{1,63}$/iu' ), + 'TM' => array( 1 => '/^[\x{002d}0-9a-zà-öø-ÿāăąćĉċčďđēėęěĝġģĥħīįĵķĺļľŀłńņňŋőœŕŗřśŝşšţťŧūŭůűųŵŷźżž]{1,63}$/iu' ), + 'TW' => 'Hostname/Cn.php', + 'TR' => array( 1 => '/^[\x{002d}0-9a-zğıüşöç]{1,63}$/iu' ), + 'UA' => array( 1 => '/^[\x{002d}0-9a-zабвгдежзийклмнопрстуфхцчшщъыьэюяѐёђѓєѕіїјљњћќѝўџґӂʼ]{1,63}$/iu' ), + 'VE' => array( 1 => '/^[\x{002d}0-9a-záéíóúüñ]{1,63}$/iu' ), + 'VN' => array( 1 => '/^[ÀÁÂÃÈÉÊÌÍÒÓÔÕÙÚÝàáâãèéêìíòóôõùúýĂăĐđĨĩŨũƠơƯư\x{1EA0}-\x{1EF9}]{1,63}$/iu' ), + 'мон' => array( 1 => '/^[\x{002d}0-9\x{0430}-\x{044F}]{1,63}$/iu' ), + 'срб' => array( 1 => '/^[\x{002d}0-9а-ик-шђјљњћџ]{1,63}$/iu' ), + 'сайт' => array( 1 => '/^[\x{002d}0-9а-яёіїѝйўґг]{1,63}$/iu' ), + 'онлайн' => array( 1 => '/^[\x{002d}0-9а-яёіїѝйўґг]{1,63}$/iu' ), + '中国' => 'Hostname/Cn.php', + '中國' => 'Hostname/Cn.php', + 'ලංකා' => array( 1 => '/^[\x{0d80}-\x{0dff}]{1,63}$/iu' ), + '香港' => 'Hostname/Cn.php', + '台湾' => 'Hostname/Cn.php', + '台灣' => 'Hostname/Cn.php', + 'امارات' => array( 1 => '/^[\x{0621}-\x{0624}\x{0626}-\x{063A}\x{0641}\x{0642}\x{0644}-\x{0648}\x{067E}\x{0686}\x{0698}\x{06A9}\x{06AF}\x{06CC}\x{06F0}-\x{06F9}]{1,30}$/iu' ), + 'الاردن' => array( 1 => '/^[\x{0621}-\x{0624}\x{0626}-\x{063A}\x{0641}\x{0642}\x{0644}-\x{0648}\x{067E}\x{0686}\x{0698}\x{06A9}\x{06AF}\x{06CC}\x{06F0}-\x{06F9}]{1,30}$/iu' ), + 'السعودية' => array( 1 => '/^[\x{0621}-\x{0624}\x{0626}-\x{063A}\x{0641}\x{0642}\x{0644}-\x{0648}\x{067E}\x{0686}\x{0698}\x{06A9}\x{06AF}\x{06CC}\x{06F0}-\x{06F9}]{1,30}$/iu' ), + 'ไทย' => array( 1 => '/^[\x{002d}0-9a-z\x{0E01}-\x{0E3A}\x{0E40}-\x{0E4D}\x{0E50}-\x{0E59}]{1,63}$/iu' ), + 'рф' => array( 1 => '/^[\x{002d}0-9а-яё]{1,63}$/iu' ), + 'تونس' => array( 1 => '/^[\x{0621}-\x{0624}\x{0626}-\x{063A}\x{0641}\x{0642}\x{0644}-\x{0648}\x{067E}\x{0686}\x{0698}\x{06A9}\x{06AF}\x{06CC}\x{06F0}-\x{06F9}]{1,30}$/iu' ), + 'مصر' => array( 1 => '/^[\x{0621}-\x{0624}\x{0626}-\x{063A}\x{0641}\x{0642}\x{0644}-\x{0648}\x{067E}\x{0686}\x{0698}\x{06A9}\x{06AF}\x{06CC}\x{06F0}-\x{06F9}]{1,30}$/iu' ), + 'இலங்கை' => array( 1 => '/^[\x{0b80}-\x{0bff}]{1,63}$/iu' ), + 'فلسطين' => array( 1 => '/^[\x{0621}-\x{0624}\x{0626}-\x{063A}\x{0641}\x{0642}\x{0644}-\x{0648}\x{067E}\x{0686}\x{0698}\x{06A9}\x{06AF}\x{06CC}\x{06F0}-\x{06F9}]{1,30}$/iu' ), + 'شبكة' => array( 1 => '/^[\x{0621}-\x{0624}\x{0626}-\x{063A}\x{0641}\x{0642}\x{0644}-\x{0648}\x{067E}\x{0686}\x{0698}\x{06A9}\x{06AF}\x{06CC}\x{06F0}-\x{06F9}]{1,30}$/iu' ), + ); + + protected $_idnLength = array( + 'BIZ' => array( 5 => 17, 11 => 15, 12 => 20 ), + 'CN' => array( 1 => 20 ), + 'COM' => array( 3 => 17, 5 => 20 ), + 'HK' => array( 1 => 15 ), + 'INFO' => array( 4 => 17 ), + 'KR' => array( 1 => 17 ), + 'NET' => array( 3 => 17, 5 => 20 ), + 'ORG' => array( 6 => 17 ), + 'TW' => array( 1 => 20 ), + 'ایران' => array( 1 => 30 ), + '中国' => array( 1 => 20 ), + '公司' => array( 1 => 20 ), + '网络' => array( 1 => 20 ), + ); + + protected $_options = array( + 'allow' => self::ALLOW_DNS, + 'idn' => true, + 'tld' => true, + 'ip' => null, + ); + + /** + * Sets validator options + * + * @see http://www.iana.org/cctld/specifications-policies-cctlds-01apr02.htm Technical Specifications for ccTLDs + * @param array $options Validator options + */ + public function __construct( $options = array() ) { + if ( $options instanceof Postman_Zend_Config ) { + $options = $options->toArray(); + } else if ( ! is_array( $options ) ) { + $options = func_get_args(); + $temp['allow'] = array_shift( $options ); + if ( ! empty( $options ) ) { + $temp['idn'] = array_shift( $options ); + } + + if ( ! empty( $options ) ) { + $temp['tld'] = array_shift( $options ); + } + + if ( ! empty( $options ) ) { + $temp['ip'] = array_shift( $options ); + } + + $options = $temp; + } + + $options += $this->_options; + $this->setOptions( $options ); + } + + /** + * Returns all set options + * + * @return array + */ + public function getOptions() { + + return $this->_options; + } + + /** + * Sets the options for this validator + * + * @param array $options + * @return Postman_Zend_Validate_Hostname + */ + public function setOptions( $options ) { + if ( array_key_exists( 'allow', $options ) ) { + $this->setAllow( $options['allow'] ); + } + + if ( array_key_exists( 'idn', $options ) ) { + $this->setValidateIdn( $options['idn'] ); + } + + if ( array_key_exists( 'tld', $options ) ) { + $this->setValidateTld( $options['tld'] ); + } + + if ( array_key_exists( 'ip', $options ) ) { + $this->setIpValidator( $options['ip'] ); + } + + return $this; + } + + /** + * Returns the set ip validator + * + * @return Postman_Zend_Validate_Ip + */ + public function getIpValidator() { + + return $this->_options['ip']; + } + + /** + * @param Postman_Zend_Validate_Ip $ipValidator OPTIONAL + * @return Postman_Zend_Validate_Hostname + */ + public function setIpValidator( Postman_Zend_Validate_Ip $ipValidator = null ) { + if ( $ipValidator === null ) { + $ipValidator = new Postman_Zend_Validate_Ip(); + } + + $this->_options['ip'] = $ipValidator; + return $this; + } + + /** + * Returns the allow option + * + * @return integer + */ + public function getAllow() { + + return $this->_options['allow']; + } + + /** + * Sets the allow option + * + * @param integer $allow + * @return Postman_Zend_Validate_Hostname Provides a fluent interface + */ + public function setAllow( $allow ) { + $this->_options['allow'] = $allow; + return $this; + } + + /** + * Returns the set idn option + * + * @return boolean + */ + public function getValidateIdn() { + + return $this->_options['idn']; + } + + /** + * Set whether IDN domains are validated + * + * This only applies when DNS hostnames are validated + * + * @param boolean $allowed Set allowed to true to validate IDNs, and false to not validate them + * @return $this + */ + public function setValidateIdn( $allowed ) { + $this->_options['idn'] = (bool) $allowed; + return $this; + } + + /** + * Returns the set tld option + * + * @return boolean + */ + public function getValidateTld() { + + return $this->_options['tld']; + } + + /** + * Set whether the TLD element of a hostname is validated + * + * This only applies when DNS hostnames are validated + * + * @param boolean $allowed Set allowed to true to validate TLDs, and false to not validate them + * @return $this + */ + public function setValidateTld( $allowed ) { + $this->_options['tld'] = (bool) $allowed; + return $this; + } + + /** + * Defined by Postman_Zend_Validate_Interface + * + * Returns true if and only if the $value is a valid hostname with respect to the current allow option + * + * @param string $value + * @throws Postman_Zend_Validate_Exception if a fatal error occurs for validation process + * @return boolean + */ + public function isValid( $value ) { + if ( ! is_string( $value ) ) { + $this->_error( self::INVALID ); + return false; + } + + $this->_setValue( $value ); + // Check input against IP address schema + if ( preg_match( '/^[0-9a-f:.]*$/i', $value ) && + $this->_options['ip']->setTranslator( $this->getTranslator() )->isValid( $value ) ) { + if ( ! ($this->_options['allow'] & self::ALLOW_IP) ) { + $this->_error( self::IP_ADDRESS_NOT_ALLOWED ); + return false; + } else { + return true; + } + } + + // RFC3986 3.2.2 states: + // + // The rightmost domain label of a fully qualified domain name + // in DNS may be followed by a single "." and should be if it is + // necessary to distinguish between the complete domain name and + // some local domain. + // + // (see ZF-6363) + // Local hostnames are allowed to be partitial (ending '.') + if ( $this->_options['allow'] & self::ALLOW_LOCAL ) { + if ( substr( $value, -1 ) === '.' ) { + $value = substr( $value, 0, -1 ); + if ( substr( $value, -1 ) === '.' ) { + // Empty hostnames (ending '..') are not allowed + $this->_error( self::INVALID_LOCAL_NAME ); + return false; + } + } + } + + $domainParts = explode( '.', $value ); + + // Prevent partitial IP V4 adresses (ending '.') + if ( (count( $domainParts ) == 4) && preg_match( '/^[0-9.a-e:.]*$/i', $value ) && + $this->_options['ip']->setTranslator( $this->getTranslator() )->isValid( $value ) ) { + $this->_error( self::INVALID_LOCAL_NAME ); + } + + // Check input against DNS hostname schema + if ( (count( $domainParts ) > 1) && (strlen( $value ) >= 4) && (strlen( $value ) <= 254) ) { + $status = false; + + $origenc = PHP_VERSION_ID < 50600 + ? iconv_get_encoding( 'internal_encoding' ) + : ini_get( 'default_charset' ); + if ( PHP_VERSION_ID < 50600 ) { + iconv_set_encoding( 'internal_encoding', 'UTF-8' ); + } else { + // jason was here + @ini_set( 'default_charset', 'UTF-8' ); + } + do { + // First check TLD + $matches = array(); + if ( preg_match( '/([^.]{2,63})$/iu', end( $domainParts ), $matches ) + || (array_key_exists( end( $domainParts ), $this->_validIdns )) ) { + reset( $domainParts ); + + // Hostname characters are: *(label dot)(label dot label); max 254 chars + // label: id-prefix [*ldh{61} id-prefix]; max 63 chars + // id-prefix: alpha / digit + // ldh: alpha / digit / dash + // Match TLD against known list + $this->_tld = $matches[1]; + if ( $this->_options['tld'] ) { + if ( ! in_array( strtolower( $this->_tld ), $this->_validTlds ) + && ! in_array( $this->_tld, $this->_validTlds ) ) { + $this->_error( self::UNKNOWN_TLD ); + $status = false; + break; + } + // We have already validated that the TLD is fine. We don't want it to go through the below + // checks as new UTF-8 TLDs will incorrectly fail if there is no IDN regex for it. + array_pop( $domainParts ); + } + + /** + * Match against IDN hostnames + * Note: Keep label regex short to avoid issues with long patterns when matching IDN hostnames + * + * @see Postman_Zend_Validate_Hostname_Interface + */ + $regexChars = array( 0 => '/^[a-z0-9\x2d]{1,63}$/i' ); + if ( $this->_options['idn'] && isset( $this->_validIdns[ strtoupper( $this->_tld ) ] ) ) { + if ( is_string( $this->_validIdns[ strtoupper( $this->_tld ) ] ) ) { + $regexChars += include( $this->_validIdns[ strtoupper( $this->_tld ) ] ); + } else { + $regexChars += $this->_validIdns[ strtoupper( $this->_tld ) ]; + } + } + + // Check each hostname part + $check = 0; + foreach ( $domainParts as $domainPart ) { + // If some domain part is empty (i.e. zend..com), it's invalid + if ( empty( $domainPart ) ) { + $this->_error( self::INVALID_HOSTNAME ); + return false; + } + + // Decode Punycode domainnames to IDN + if ( strpos( $domainPart, 'xn--' ) === 0 ) { + $domainPart = $this->decodePunycode( substr( $domainPart, 4 ) ); + if ( $domainPart === false ) { + return false; + } + } + + // Check dash (-) does not start, end or appear in 3rd and 4th positions + if ( (strpos( $domainPart, '-' ) === 0) + || ((strlen( $domainPart ) > 2) && (strpos( $domainPart, '-', 2 ) == 2) && (strpos( $domainPart, '-', 3 ) == 3)) + || (strpos( $domainPart, '-' ) === (strlen( $domainPart ) - 1)) ) { + $this->_error( self::INVALID_DASH ); + $status = false; + break 2; + } + + // Check each domain part + $checked = false; + foreach ( $regexChars as $regexKey => $regexChar ) { + $status = preg_match( $regexChar, $domainPart ); + if ( $status > 0 ) { + $length = 63; + if ( array_key_exists( strtoupper( $this->_tld ), $this->_idnLength ) + && (array_key_exists( $regexKey, $this->_idnLength[ strtoupper( $this->_tld ) ] )) ) { + $length = $this->_idnLength[ strtoupper( $this->_tld ) ]; + } + + if ( iconv_strlen( $domainPart, 'UTF-8' ) > $length ) { + $this->_error( self::INVALID_HOSTNAME ); + } else { + $checked = true; + break; + } + } + } + + if ( $checked ) { + ++$check; + } + } + + // If one of the labels doesn't match, the hostname is invalid + if ( $check !== count( $domainParts ) ) { + $this->_error( self::INVALID_HOSTNAME_SCHEMA ); + $status = false; + } + } else { + // Hostname not long enough + $this->_error( self::UNDECIPHERABLE_TLD ); + $status = false; + } + } while (false); + + if ( PHP_VERSION_ID < 50600 ) { + iconv_set_encoding( 'internal_encoding', $origenc ); + } else { + // jason was here + @ini_set( 'default_charset', $origenc ); + } + // If the input passes as an Internet domain name, and domain names are allowed, then the hostname + // passes validation + if ( $status && ($this->_options['allow'] & self::ALLOW_DNS) ) { + return true; + } + } else if ( $this->_options['allow'] & self::ALLOW_DNS ) { + $this->_error( self::INVALID_HOSTNAME ); + } + + // Check for URI Syntax (RFC3986) + if ( $this->_options['allow'] & self::ALLOW_URI ) { + if ( preg_match( "/^([a-zA-Z0-9-._~!$&\'()*+,;=]|%[[:xdigit:]]{2}){1,254}$/i", $value ) ) { + return true; + } else { + $this->_error( self::INVALID_URI ); + } + } + + // Check input against local network name schema; last chance to pass validation + $regexLocal = '/^(([a-zA-Z0-9\x2d]{1,63}\x2e)*[a-zA-Z0-9\x2d]{1,63}[\x2e]{0,1}){1,254}$/'; + $status = @preg_match( $regexLocal, $value ); + + // If the input passes as a local network name, and local network names are allowed, then the + // hostname passes validation + $allowLocal = $this->_options['allow'] & self::ALLOW_LOCAL; + if ( $status && $allowLocal ) { + return true; + } + + // If the input does not pass as a local network name, add a message + if ( ! $status ) { + $this->_error( self::INVALID_LOCAL_NAME ); + } + + // If local network names are not allowed, add a message + if ( $status && ! $allowLocal ) { + $this->_error( self::LOCAL_NAME_NOT_ALLOWED ); + } + + return false; + } + + /** + * Decodes a punycode encoded string to it's original utf8 string + * In case of a decoding failure the original string is returned + * + * @param string $encoded Punycode encoded string to decode + * @return string + */ + protected function decodePunycode( $encoded ) { + if ( ! preg_match( '/^[a-z0-9-]+$/i', $encoded ) ) { + // no punycode encoded string + $this->_error( self::CANNOT_DECODE_PUNYCODE ); + return false; + } + + $decoded = array(); + $separator = strrpos( $encoded, '-' ); + if ( $separator > 0 ) { + for ( $x = 0; $x < $separator; ++$x ) { + // prepare decoding matrix + $decoded[] = ord( $encoded[ $x ] ); + } + } + + $lengthd = count( $decoded ); + $lengthe = strlen( $encoded ); + + // decoding + $init = true; + $base = 72; + $index = 0; + $char = 0x80; + + for ( $indexe = ($separator) ? ($separator + 1) : 0; $indexe < $lengthe; ++$lengthd ) { + for ( $old_index = $index, $pos = 1, $key = 36; 1 ; $key += 36 ) { + $hex = ord( $encoded[ $indexe++ ] ); + $digit = ($hex - 48 < 10) ? $hex - 22 + : (($hex - 65 < 26) ? $hex - 65 + : (($hex - 97 < 26) ? $hex - 97 + : 36)); + + $index += $digit * $pos; + $tag = ($key <= $base) ? 1 : (($key >= $base + 26) ? 26 : ($key - $base)); + if ( $digit < $tag ) { + break; + } + + $pos = (int) ($pos * (36 - $tag)); + } + + $delta = intval( $init ? (($index - $old_index) / 700) : (($index - $old_index) / 2) ); + $delta += intval( $delta / ($lengthd + 1) ); + for ( $key = 0; $delta > 910 / 2; $key += 36 ) { + $delta = intval( $delta / 35 ); + } + + $base = intval( $key + 36 * $delta / ($delta + 38) ); + $init = false; + $char += (int) ($index / ($lengthd + 1)); + $index %= ($lengthd + 1); + if ( $lengthd > 0 ) { + for ( $i = $lengthd; $i > $index; $i-- ) { + $decoded[ $i ] = $decoded[ ($i - 1) ]; + } + } + + $decoded[ $index++ ] = $char; + } + + // convert decoded ucs4 to utf8 string + foreach ( $decoded as $key => $value ) { + if ( $value < 128 ) { + $decoded[ $key ] = chr( $value ); + } elseif ( $value < (1 << 11) ) { + $decoded[ $key ] = chr( 192 + ($value >> 6) ); + $decoded[ $key ] .= chr( 128 + ($value & 63) ); + } elseif ( $value < (1 << 16) ) { + $decoded[ $key ] = chr( 224 + ($value >> 12) ); + $decoded[ $key ] .= chr( 128 + (($value >> 6) & 63) ); + $decoded[ $key ] .= chr( 128 + ($value & 63) ); + } elseif ( $value < (1 << 21) ) { + $decoded[ $key ] = chr( 240 + ($value >> 18) ); + $decoded[ $key ] .= chr( 128 + (($value >> 12) & 63) ); + $decoded[ $key ] .= chr( 128 + (($value >> 6) & 63) ); + $decoded[ $key ] .= chr( 128 + ($value & 63) ); + } else { + $this->_error( self::CANNOT_DECODE_PUNYCODE ); + return false; + } + } + + return implode( $decoded ); + } } diff --git a/Postman/Postman.php b/Postman/Postman.php index aabdff3..23351e7 100644 --- a/Postman/Postman.php +++ b/Postman/Postman.php @@ -16,7 +16,7 @@ */ class Postman { - const ADMINISTRATOR_ROLE_NAME = 'administrator'; + const ADMINISTRATOR_ROLE_NAME = 'administrator'; const MANAGE_POSTMAN_CAPABILITY_NAME = 'manage_postman_smtp'; const TEXT_DOMAIN = 'post-smtp'; @@ -250,7 +250,26 @@ class Postman { // on any admin pages, show this error message // I noticed the wpMandrill and SendGrid plugins have the exact same error message here // I've adopted their error message as well, for shits and giggles .... :D + $reflFunc = new ReflectionFunction( 'wp_mail' ); + $message = __( 'Postman: wp_mail has been declared by another plugin or theme, so you won\'t be able to use Postman until the conflict is resolved.', Postman::TEXT_DOMAIN ); + $plugin_full_path = $reflFunc->getFileName(); + + if ( strpos( $plugin_full_path, 'plugins' ) !== false ) { + + require_once ABSPATH . '/wp-admin/includes/plugin.php'; + + preg_match( '/([a-z]+\/[a-z]+\.php)$/', $plugin_full_path, $output_array ); + + $plugin_file = $output_array[1]; + $plugin_data = get_plugin_data( $plugin_full_path ); + + $deactivate_url = '<a href="' . wp_nonce_url( 'plugins.php?action=deactivate&plugin=' . urlencode( $plugin_file ) . '&plugin_status=active&paged=1&s=deactivate-plugin_' . $plugin_file ) . '" aria-label="' . esc_attr( sprintf( _x( 'Deactivate %s', 'plugin' ), $plugin_data['Name'] ) ) . '">' . __( 'Deactivate' ) . '</a><br>'; + $message .= '<br><strong>Plugin Name:</strong> ' . $plugin_data['Name']; + $message .= '<br>' . $deactivate_url; + } + + $message .= '<br><strong>More info that may help</strong> - ' . $reflFunc->getFileName() . ':' . $reflFunc->getStartLine(); $this->messageHandler->addError( $message ); } } else { @@ -392,4 +411,3 @@ if ( ! function_exists( 'str_getcsv' ) ) { return PostmanUtils::postman_strgetcsv_impl( $string ); } } - diff --git a/Postman/PostmanAdminController.php b/Postman/PostmanAdminController.php index c9d0c5d..9758b55 100644 --- a/Postman/PostmanAdminController.php +++ b/Postman/PostmanAdminController.php @@ -137,6 +137,8 @@ if ( ! class_exists( 'PostmanAdminController' ) ) { $this, 'postmanModifyLinksOnPluginsListPage', ) ); + + require_once( 'PostmanPluginFeedback.php' ); } /** diff --git a/Postman/PostmanPluginFeedback.php b/Postman/PostmanPluginFeedback.php new file mode 100644 index 0000000..562d8a5 --- /dev/null +++ b/Postman/PostmanPluginFeedback.php @@ -0,0 +1,131 @@ +<?php + +class PostmanPluginFeedback { + function __construct() { + add_filter( 'plugin_action_links_' . plugin_basename( POST_BASE ), array( $this, 'insert_deactivate_link_id' ) ); + add_action( 'wp_ajax_post_user_feedback', array( $this, 'post_user_feedback' ) ); + + global $pagenow; + if ( 'plugins.php' === $pagenow ) { + add_action( 'admin_enqueue_scripts', array( $this, 'load_scripts' ) ); + add_action( 'admin_head', array( $this, 'admin_head' ) ); + add_action( 'admin_footer', array( $this, 'add_deactivation_dialog' ) ); + } + } + + function load_scripts() { + wp_enqueue_style( 'wp-jquery-ui-dialog' ); + wp_register_script( 'post-feedback', plugins_url( 'script/feedback/feedback.js', POST_BASE ), array( 'jquery', 'jquery-ui-core', 'jquery-ui-dialog' ), fasle, true ); + wp_localize_script( 'post-feedback', 'post_feedback', array( 'admin_ajax' => admin_url( 'admin-ajax.php' ) ) ); + wp_enqueue_script( 'post-feedback' ); + } + + function post_user_feedback() { + if ( ! check_ajax_referer() ) { + die( 'security error' ); + } + + $payload = array( + 'reason' => sanitize_text_field( $_POST['reason'] ), + 'other_input' => isset( $_POST['other_input'] ) ? sanitize_textarea_field( $_POST['other_input'] ) : '', + ); + + if ( isset( $_POST['support'] ) ) { + $payload['support']['email'] = sanitize_email( $_POST['support']['email'] ); + $payload['support']['title'] = sanitize_email( $_POST['support']['title'] ); + $payload['support']['text'] = sanitize_textarea_field( $_POST['support']['text'] ); + } + + $args = array( + 'body' => $payload, + ); + $result = wp_remote_post( 'https://postmansmtp.com/feedback', $args ); + die(); + } + + function admin_head() { + ?> + <style type="text/css"> + .postman-feedback-dialog-form .ui-dialog-buttonset { + float: none !important; + } + + #postman-feedback-dialog-skip { + float: left; + } + + #postman-feedback-dialog-go, #postman-feedback-dialog-cancel { + float: right; + } + + #postman-feedback-dialog-content p { + font-size: 1.1em; + } + + #postman-deactivate-reasons textarea { + margin-top: 10px; + width: 100%; + height: 150px; + } + </style> + <?php + } + + function insert_deactivate_link_id( $links ) { + $links['deactivate'] = str_replace( '<a', '<a id="postman-plugin-disbale-link"', $links['deactivate'] ); + + return $links; + } + + function add_deactivation_dialog() { + ?> + <div id="postman-feedback-dialog-content" style="display: none;"> + <p> + I feel bad to see anyone stop using Post SMTP.<br> + I would love to get a small feedback from you. + </p> + <form> + <?php wp_nonce_field(); ?> + <ul id="postman-deactivate-reasons"> + <li class="postman-reason postman-custom-input"> + <label> + <span><input value="Found a better plugin" type="radio" name="reason" /></span> + <span><?php _e( 'Found a better plugin', 'postman' ); ?></span> + </label> + <div class="postman-reason-input" style="display: none;"> + <textarea name="other_input"></textarea> + </div> + </li> + <li class="postman-reason"> + <label> + <span><input value="The plugin didn't work" type="radio" name="reason" /></span> + <span><?php _e( 'The plugin didn\'t work', 'postman' ); ?></span> + </label> + </li> + <li class="postman-reason postman-custom-input"> + <label> + <span><input value="Other Reason" type="radio" name="reason" /></span> + <span><?php _e( 'Other Reason', 'postman' ); ?></span> + </label> + <div class="postman-reason-input" style="display: none;"> + <textarea name="other_input"></textarea> + </div> + </li> + <li class="postman-reason postman-custom-input"> + <label> + <span><input value="Support Ticket" type="radio" name="reason" /></span> + <span><?php _e( 'Open A support ticket for me', 'postman' ); ?></span> + </label> + <div class="postman-reason-input" style="display: none;"> + <input type="email" name="support[email]" placeholder="Your Email Address" required> + <input type="text" name="support[title]" placeholder="The Title" required> + <textarea name="support[text]" placeholder="Describe the issue" required></textarea> + </div> + </li> + </ul> + </form> + </div> + <?php + } +} +new PostmanPluginFeedback; diff --git a/Postman/PostmanViewController.php b/Postman/PostmanViewController.php index f9d6d2a..2ce4d2b 100644 --- a/Postman/PostmanViewController.php +++ b/Postman/PostmanViewController.php @@ -97,7 +97,9 @@ if ( ! class_exists( 'PostmanViewController' ) ) { wp_register_style( 'jquery_steps_style', plugins_url( 'style/jquery-steps/jquery.steps.css', $this->rootPluginFilenameAndPath ), PostmanViewController::POSTMAN_STYLE, '1.1.0' ); wp_register_script( PostmanViewController::POSTMAN_SCRIPT, plugins_url( 'script/postman.js', $this->rootPluginFilenameAndPath ), array( - PostmanViewController::JQUERY_SCRIPT + PostmanViewController::JQUERY_SCRIPT, + 'jquery-ui-core', + 'jquery-ui-datepicker', ), $pluginData ['version'] ); wp_register_script( 'sprintf', plugins_url( 'script/sprintf/sprintf.min.js', $this->rootPluginFilenameAndPath ), null, '1.0.2' ); wp_register_script( 'jquery_steps_script', plugins_url( 'script/jquery-steps/jquery.steps.min.js', $this->rootPluginFilenameAndPath ), array( @@ -159,7 +161,7 @@ if ( ! class_exists( 'PostmanViewController' ) ) { if ( PostmanState::getInstance()->isTimeToReviewPostman() && ! PostmanOptions::getInstance()->isNew() ) { print '</br><hr width="70%"></br>'; /* translators: where %s is the URL to the WordPress.org review and ratings page */ - printf( '%s</span></p>', sprintf( __( 'Please consider <a href="%s">leaving a review</a> to help spread the word! :D', Postman::TEXT_DOMAIN ), 'https://wordpress.org/support/view/plugin-reviews/postman-smtp?filter=5' ) ); + printf( '%s</span></p>', sprintf( __( 'Please consider <a href="%s">leaving a review</a> to help spread the word! :D', Postman::TEXT_DOMAIN ), 'https://wordpress.org/support/view/plugin-reviews/post-smtp?filter=5' ) ); } printf( '<p><span>%s :-)</span></p>', sprintf( __( 'Postman needs translators! Please take a moment to <a href="%s">translate a few sentences on-line</a>', Postman::TEXT_DOMAIN ), 'https://translate.wordpress.org/projects/wp-plugins/post-smtp/stable' ) ); } @@ -292,8 +294,8 @@ if ( ! class_exists( 'PostmanViewController' ) ) { print '<ul>'; printf( '<li><a href="%s" class="welcome-icon run-port-test">%s</a></li>', $this->getPageUrl( PostmanConnectivityTestController::PORT_TEST_SLUG ), __( 'Connectivity Test', Postman::TEXT_DOMAIN ) ); printf( '<li><a href="%s" class="welcome-icon run-port-test">%s</a></li>', $this->getPageUrl( PostmanDiagnosticTestController::DIAGNOSTICS_SLUG ), __( 'Diagnostic Test', Postman::TEXT_DOMAIN ) ); - printf( '<li><a href="https://wordpress.org/support/plugin/post-smtp" class="welcome-icon postman_support">%s</a></li>', __( 'Online Support', Postman::TEXT_DOMAIN ) ); - printf( '<li><div class="new-item"><span>New</span></div><a href="https://postmansmtp.com/category/guides/" class="welcome-icon postman_guides">%s</a></li>', __( 'Guides', Postman::TEXT_DOMAIN ) ); + printf( '<li><a href="https://postmansmtp.com/forums/" class="welcome-icon postman_support">%s</a></li>', __( 'Online Support', Postman::TEXT_DOMAIN ) ); + printf( '<li><img class="align-middle" src="' . plugins_url( 'style/images/new.gif', dirname( __DIR__ ) . '/postman-smtp.php' ) . '"><a class="align-middle" href="https://postmansmtp.com/category/guides/" class="welcome-icon postman_guides">%s</a></li>', __( 'Guides', Postman::TEXT_DOMAIN ) ); print '</ul></div></div></div></div>'; } } diff --git a/postman-smtp.php b/postman-smtp.php index df55233..21a3911 100644 --- a/postman-smtp.php +++ b/postman-smtp.php @@ -35,6 +35,7 @@ * DO some check and Start Postman */ +define( 'POST_BASE', __FILE__ ); if ( in_array( 'postman-smtp/postman-smtp.php', (array) get_option( 'active_plugins', array() ) ) ) { add_action( 'admin_init', 'post_smtp_plugin_deactivate' ); @@ -11,6 +11,9 @@ Send, log and troubleshoot your Outgoing Email easily. Supports everything: SMTP == Description == += From now all the support is made on Post SMTP forums = +https://postmansmtp.com/forums/ + = Postman SMTP is back! = Now under new maintenance, no need to search for another SMTP plugin anymore. @@ -282,6 +285,7 @@ To avoid being flagged as spam, you need to prove your email isn't forged. On a * Fixed: IP detection error in some web hosts * Fixed: Link open in new page attribute = _blank * Fixed: Replace deprecated PHP 7 functions. +* Updated: Validator TLD's list = 1.7.7 - 2017-10-17 * Fixed: Error sending files with sendgrid diff --git a/script/feedback/feedback.js b/script/feedback/feedback.js new file mode 100644 index 0000000..97940cf --- /dev/null +++ b/script/feedback/feedback.js @@ -0,0 +1,73 @@ +jQuery(document).ready(function($) { + + $( '#the-list #postman-plugin-disbale-link' ).click(function(e) { + e.preventDefault(); + + var reason = $( '#postman-feedback-dialog-content .postman-reason' ), + deactivateLink = $( this ).attr( 'href' ); + + $( "#postman-feedback-dialog-content" ).dialog({ + title: 'Post SMTP Feedback Form', + dialogClass: 'postman-feedback-dialog-form', + resizable: false, + minWidth: 400, + minHeight: 300, + modal: true, + buttons: { + 'skip' : { + text: 'Skip', + id: 'postman-feedback-dialog-skip', + click: function() { + $( this ).dialog( "close" ); + + location.href = deactivateLink; + } + }, + 'go' : { + text: 'Continue', + id: 'postman-feedback-dialog-go', + class: 'button', + click: function() { + $( this ).dialog( "close" ); + + var form = $( this ).find( 'form' ).serializeArray(), + result = {}; + + $.each( form, function() { + if ( '' !== this.value ) + result[ this.name ] = this.value; + }); + + if ( ! jQuery.isEmptyObject( result ) ) { + result.action = 'post_user_feedback'; + + $.post( post_feedback.admin_ajax, result, function(result) { + + }); + } + + // Remove this comment to deactivate plugin + location.href = deactivateLink; + }, + }, + 'cancel' : { + text: 'Cancel', + id: 'postman-feedback-dialog-cancel', + class: 'button button-primary', + click: function() { + $( this ).dialog( "close" ); + } + } + } + }); + + reason.change(function() { + $( '.postman-reason-input' ).hide(); + + if ( $( this ).hasClass( 'postman-custom-input' ) ) { + $( this ).find( '.postman-reason-input' ).show(); + } + }); + + }); +});
\ No newline at end of file diff --git a/script/postman.js b/script/postman.js index f019dbb..c6c0e98 100644 --- a/script/postman.js +++ b/script/postman.js @@ -1,3 +1,7 @@ +jQuery(document).ready(function($) { + $( ".email-log-date" ).datepicker(); +}); + var redirectUrlWarning = false; if (!console) console = { diff --git a/style/postman-email-log.css b/style/postman-email-log.css index e9f9ce6..1142767 100644 --- a/style/postman-email-log.css +++ b/style/postman-email-log.css @@ -3,3 +3,366 @@ th#date { width:15%; } + +#email-log-filter { + padding: 20px; + display: flex; + justify-content: space-around; + align-items: center; + border-bottom: 1px solid #ddd; +} + +#email-log-filter label { + font-weight: bold; + font-size: 1em; +} + +#email-log-filter input { + padding: 10px; + border-radius: 5px; +} + + +/* Date Picker Default Styles */ +.ui-datepicker { + padding: 0; + margin: 0; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + background-color: #fff; + border: 1px solid #dfdfdf; + border-top: none; + -webkit-box-shadow: 0 3px 6px rgba(0, 0, 0, 0.075); + box-shadow: 0 3px 6px rgba(0, 0, 0, 0.075); + min-width: 17em; + width: auto; +} + +.ui-datepicker * { + padding: 0; + font-family: "Open Sans", sans-serif; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.ui-datepicker table { + font-size: 13px; + margin: 0; + border: none; + border-collapse: collapse; +} + +.ui-datepicker .ui-widget-header, +.ui-datepicker .ui-datepicker-header { + background-image: none; + border: none; + color: #fff; + font-weight: normal; +} + +.ui-datepicker .ui-datepicker-header .ui-state-hover { + background: transparent; + border-color: transparent; + cursor: pointer; +} + +.ui-datepicker .ui-datepicker-title { + margin: 0; + padding: 10px 0; + color: #fff; + font-size: 14px; + line-height: 14px; + text-align: center; +} + +.ui-datepicker .ui-datepicker-prev, +.ui-datepicker .ui-datepicker-next { + position: relative; + top: 0; + height: 34px; + width: 34px; +} + +.ui-datepicker .ui-state-hover.ui-datepicker-prev, +.ui-datepicker .ui-state-hover.ui-datepicker-next { + border: none; +} + +.ui-datepicker .ui-datepicker-prev, +.ui-datepicker .ui-datepicker-prev-hover { + left: 0; +} + +.ui-datepicker .ui-datepicker-next, +.ui-datepicker .ui-datepicker-next-hover { + right: 0; +} + +.ui-datepicker .ui-datepicker-next span, +.ui-datepicker .ui-datepicker-prev span { + display: none; +} + +.ui-datepicker .ui-datepicker-prev { + float: left; +} + +.ui-datepicker .ui-datepicker-next { + float: right; +} + +.ui-datepicker .ui-datepicker-prev:before, +.ui-datepicker .ui-datepicker-next:before { + font: normal 20px/34px 'dashicons'; + padding-left: 7px; + color: #fff; + speak: none; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + width: 34px; + height: 34px; +} + +.ui-datepicker .ui-datepicker-prev:before { + content: '\f341'; +} + +.ui-datepicker .ui-datepicker-next:before { + content: '\f345'; +} + +.ui-datepicker .ui-datepicker-prev-hover:before, +.ui-datepicker .ui-datepicker-next-hover:before { + opacity: 0.7; +} + +.ui-datepicker select.ui-datepicker-month, +.ui-datepicker select.ui-datepicker-year { + width: 33%; +} + +.ui-datepicker thead { + color: #fff; + font-weight: 600; +} + +.ui-datepicker th { + padding: 10px; +} + +.ui-datepicker td { + padding: 0; + border: 1px solid #f4f4f4; +} + +.ui-datepicker td.ui-datepicker-other-month { + border: transparent; +} + +.ui-datepicker td.ui-datepicker-week-end { + background-color: #f4f4f4; + border: 1px solid #f4f4f4; +} + +.ui-datepicker td.ui-datepicker-today { + background-color: #f0f0c0; +} + +.ui-datepicker td.ui-datepicker-current-day { + background: #bbdd88; +} + +.ui-datepicker td .ui-state-default { + background: transparent; + border: none; + text-align: center; + text-decoration: none; + width: auto; + display: block; + padding: 5px 10px; + font-weight: normal; + color: #444; +} + +.ui-datepicker td.ui-state-disabled .ui-state-default { + opacity: 0.5; +} + +/* Default Color Scheme */ +.ui-datepicker .ui-widget-header, +.ui-datepicker .ui-datepicker-header { + background: #00a0d2; +} + +.ui-datepicker thead { + background: #32373c; +} + +.ui-datepicker td .ui-state-hover { + background: #0073aa; + color: #fff; +} + +/* WordPress Color Schemes */ + +/* Fresh */ +.admin-color-fresh .ui-datepicker .ui-widget-header, +.admin-color-fresh .ui-datepicker .ui-datepicker-header { + background: #00a0d2; +} + +.admin-color-fresh .ui-datepicker thead { + background: #32373c; +} + +.admin-color-fresh .ui-datepicker td .ui-state-hover { + background: #0073aa; + color: #fff; +} + +/* Blue */ +.admin-color-blue .ui-datepicker .ui-widget-header, +.admin-color-blue .ui-datepicker .ui-datepicker-header { + background: #52accc; +} + +.admin-color-blue .ui-datepicker thead { + background: #4796b3; +} + +.admin-color-blue .ui-datepicker td .ui-state-hover { + background: #096484; + color: #fff; +} + +/* Coffee */ +.admin-color-coffee .ui-datepicker .ui-widget-header, +.admin-color-coffee .ui-datepicker .ui-datepicker-header { + background: #59524c; +} + +.admin-color-coffee .ui-datepicker thead { + background: #46403c; +} + +.admin-color-coffee .ui-datepicker td .ui-state-hover { + background: #c7a589; + color: #fff; +} + +/* Ectoplasm */ +.admin-color-ectoplasm .ui-datepicker .ui-widget-header, +.admin-color-ectoplasm .ui-datepicker .ui-datepicker-header { + background: #523f6d; +} + +.admin-color-ectoplasm .ui-datepicker thead { + background: #413256; +} + +.admin-color-ectoplasm .ui-datepicker td .ui-state-hover { + background: #a3b745; + color: #fff; +} + +/* Midnight */ +.admin-color-midnight .ui-datepicker .ui-widget-header, +.admin-color-midnight .ui-datepicker .ui-datepicker-header { + background: #363b3f; +} + +.admin-color-midnight .ui-datepicker thead { + background: #26292c; +} + +.admin-color-midnight .ui-datepicker td .ui-state-hover { + background: #e14d43; + color: #fff; +} + +/* Ocean */ +.admin-color-ocean .ui-datepicker .ui-widget-header, +.admin-color-ocean .ui-datepicker .ui-datepicker-header { + background: #738e96; +} + +.admin-color-ocean .ui-datepicker thead { + background: #627c83; +} + +.admin-color-ocean .ui-datepicker td .ui-state-hover { + background: #9ebaa0; + color: #fff; +} + +/* Sunrise */ +.admin-color-sunrise .ui-datepicker .ui-widget-header, +.admin-color-sunrise .ui-datepicker .ui-datepicker-header, +.admin-color-sunrise .ui-datepicker .ui-datepicker-header .ui-state-hover { + background: #cf4944; +} + +.admin-color-sunrise .ui-datepicker th { + border-color: #be3631; + background: #be3631; +} + +.admin-color-sunrise .ui-datepicker td .ui-state-hover { + background: #dd823b; + color: #fff; +} + +/* Light */ +.admin-color-light .ui-datepicker .ui-widget-header, +.admin-color-light .ui-datepicker .ui-datepicker-header { + background: #e5e5e5; +} + +.admin-color-light .ui-datepicker thead { + background: #888; +} + +.admin-color-light .ui-datepicker .ui-datepicker-title, +.admin-color-light .ui-datepicker td .ui-state-default, +.admin-color-light .ui-datepicker .ui-datepicker-prev:before, +.admin-color-light .ui-datepicker .ui-datepicker-next:before { + color: #555; +} + +.admin-color-light .ui-datepicker td .ui-state-hover { + background: #e5e5e5; +} + +/* bbPress Color Schemes */ + +/* Evergreen */ +.admin-color-bbp-evergreen .ui-datepicker .ui-widget-header, +.admin-color-bbp-evergreen .ui-datepicker .ui-datepicker-header { + background: #56b274; +} + +.admin-color-bbp-evergreen .ui-datepicker thead { + background: #36533f; +} + +.admin-color-bbp-evergreen .ui-datepicker td .ui-state-hover { + background: #446950; + color: #fff; +} + +/* Mint */ +.admin-color-bbp-mint .ui-datepicker .ui-widget-header, +.admin-color-bbp-mint .ui-datepicker .ui-datepicker-header { + background: #4ca26a; +} + +.admin-color-bbp-mint .ui-datepicker thead { + background: #4f6d59; +} + +.admin-color-bbp-mint .ui-datepicker td .ui-state-hover { + background: #5fb37c; + color: #fff; +} diff --git a/style/postman.css b/style/postman.css index 734f783..08cc9de 100644 --- a/style/postman.css +++ b/style/postman.css @@ -97,6 +97,12 @@ p#back_to_main_menu { animation: pulse 2s linear 0s infinite; } +.align-middle { + display: inline-block; + vertical-align: middle; +} + + @keyframes pulse { 0% { opacity: 0; |