summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoryehudah <yehudah@b8457f37-d9ea-0310-8a92-e5e31aec5664>2017-11-15 07:56:14 +0000
committeryehudah <yehudah@b8457f37-d9ea-0310-8a92-e5e31aec5664>2017-11-15 07:56:14 +0000
commitfa49f47e2f3db3115a9af66ebd404bb66d0c520b (patch)
tree93ac07583b93af5012faaf84df614aa52124e688
parent373f5e27dcb5b78d5d5af54739b17466f4dcf1ab (diff)
downloadPost-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.php31
-rw-r--r--Postman/Postman-Email-Log/PostmanEmailLogView.php237
-rw-r--r--Postman/Postman-Mail/Zend-1.12.10/Validate/Hostname.php3928
-rw-r--r--Postman/Postman.php22
-rw-r--r--Postman/PostmanAdminController.php2
-rw-r--r--Postman/PostmanPluginFeedback.php131
-rw-r--r--Postman/PostmanViewController.php10
-rw-r--r--postman-smtp.php1
-rw-r--r--readme.txt4
-rw-r--r--script/feedback/feedback.js73
-rw-r--r--script/postman.js4
-rw-r--r--style/postman-email-log.css363
-rw-r--r--style/postman.css6
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&amp;plugin=' . urlencode( $plugin_file ) . '&amp;plugin_status=active&amp;paged=1&amp;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' );
diff --git a/readme.txt b/readme.txt
index 3fa0acc..b767252 100644
--- a/readme.txt
+++ b/readme.txt
@@ -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;