diff --git a/.gitignore b/.gitignore index 54c6630..8c3312d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ .DS_Store *.pyc -/*.zip \ No newline at end of file +/*.zip +*.db +.idea/ \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..8579e47 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,8 @@ +language: php +php: + - '5.4' + - '5.5' + - '5.6' + - '7.0' + - hhvm + - nightly diff --git a/README.rst b/README.rst index 7099fa1..733e785 100644 --- a/README.rst +++ b/README.rst @@ -1,3 +1,5 @@ +.. image:: https://travis-ci.org/disqus/disqus-wordpress.svg + See disqus/readme.txt for more information Packaging @@ -14,4 +16,4 @@ The *very* limited test suite requires PHPUnit 3.6 and can be run with:: php tests.php -.. note:: If it asks for a password, this is simply the SQL user's password. \ No newline at end of file +.. note:: If it asks for a password, this is simply the SQL user's password. diff --git a/disqus/LICENSE b/disqus/LICENSE index f171204..14ea468 100644 --- a/disqus/LICENSE +++ b/disqus/LICENSE @@ -632,7 +632,7 @@ state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Disqus WordPress Plugin - Copyright (C) 2010 DISQUS + Copyright (C) 2016 Disqus This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -652,7 +652,7 @@ Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: - Disqus WordPress Plugin Copyright (C) 2010 DISQUS + Disqus WordPress Plugin Copyright (C) 2016 Disqus This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. @@ -671,4 +671,4 @@ into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read -. \ No newline at end of file +. diff --git a/disqus/assets/banner-772x250.png b/disqus/assets/banner-772x250.png new file mode 100644 index 0000000..cfaca6b Binary files /dev/null and b/disqus/assets/banner-772x250.png differ diff --git a/disqus/assets/icon-256x256.png b/disqus/assets/icon-256x256.png new file mode 100644 index 0000000..3a9f5dc Binary files /dev/null and b/disqus/assets/icon-256x256.png differ diff --git a/disqus/assets/icon.svg b/disqus/assets/icon.svg new file mode 100644 index 0000000..c6169ad --- /dev/null +++ b/disqus/assets/icon.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/disqus/assets/screenshot-1.png b/disqus/assets/screenshot-1.png new file mode 100644 index 0000000..cac1c2e Binary files /dev/null and b/disqus/assets/screenshot-1.png differ diff --git a/disqus/assets/screenshot-10.png b/disqus/assets/screenshot-10.png new file mode 100644 index 0000000..7e79af8 Binary files /dev/null and b/disqus/assets/screenshot-10.png differ diff --git a/disqus/assets/screenshot-11.png b/disqus/assets/screenshot-11.png new file mode 100644 index 0000000..33fef21 Binary files /dev/null and b/disqus/assets/screenshot-11.png differ diff --git a/disqus/assets/screenshot-2.png b/disqus/assets/screenshot-2.png new file mode 100644 index 0000000..72c0614 Binary files /dev/null and b/disqus/assets/screenshot-2.png differ diff --git a/disqus/assets/screenshot-3.png b/disqus/assets/screenshot-3.png new file mode 100644 index 0000000..d66a52a Binary files /dev/null and b/disqus/assets/screenshot-3.png differ diff --git a/disqus/assets/screenshot-4.png b/disqus/assets/screenshot-4.png new file mode 100644 index 0000000..790a7cd Binary files /dev/null and b/disqus/assets/screenshot-4.png differ diff --git a/disqus/assets/screenshot-5.png b/disqus/assets/screenshot-5.png new file mode 100644 index 0000000..f70f04d Binary files /dev/null and b/disqus/assets/screenshot-5.png differ diff --git a/disqus/assets/screenshot-6.png b/disqus/assets/screenshot-6.png new file mode 100644 index 0000000..293951b Binary files /dev/null and b/disqus/assets/screenshot-6.png differ diff --git a/disqus/assets/screenshot-7.png b/disqus/assets/screenshot-7.png new file mode 100644 index 0000000..ca2c341 Binary files /dev/null and b/disqus/assets/screenshot-7.png differ diff --git a/disqus/assets/screenshot-8.png b/disqus/assets/screenshot-8.png new file mode 100644 index 0000000..1477652 Binary files /dev/null and b/disqus/assets/screenshot-8.png differ diff --git a/disqus/assets/screenshot-9.png b/disqus/assets/screenshot-9.png new file mode 100644 index 0000000..c5553fe Binary files /dev/null and b/disqus/assets/screenshot-9.png differ diff --git a/disqus/comments.php b/disqus/comments.php index dc125b2..74e596f 100644 --- a/disqus/comments.php +++ b/disqus/comments.php @@ -6,17 +6,18 @@
-
1 && get_option('page_comments')): // Are there comments to navigate through? ?> @@ -31,8 +32,14 @@ 1 && get_option('page_comments')): // Are there comments to navigate through? ?> @@ -41,94 +48,109 @@
- - - + ?> + + this.language = ''; + + this.callbacks.onReady.push(function () { + + // sync comments in the background so we don't block the page + var script = document.createElement('script'); + script.async = true; + script.src = '?cf_action=sync_comments&post_id=ID ); ?>'; + + var firstScript = document.getElementsByTagName('script')[0]; + firstScript.parentNode.insertBefore(script, firstScript); + }); + + + if (disqus_config_custom) { + disqus_config_custom.call(this); + } +}; - + + diff --git a/disqus/disqus.php b/disqus/disqus.php index 84d186b..954f0d2 100644 --- a/disqus/disqus.php +++ b/disqus/disqus.php @@ -1,41 +1,28 @@ -Version: 2.74 -Author URI: http://disqus.com/ +Version: 2.86 +Author URI: https://disqus.com/ */ -/*. - require_module 'standard'; - require_module 'pcre'; - require_module 'mysql'; -.*/ - require_once(dirname(__FILE__) . '/lib/wp-api.php'); -if (defined('DISQUS_LOCAL')) { // DISQUS defines this for local development purposes - define('DISQUS_DOMAIN', 'dev.disqus.org:8000'); - define('DISQUS_IMPORTER_URL', 'http://dev.disqus.org:8001/'); -} else { - define('DISQUS_DOMAIN', 'disqus.com'); - define('DISQUS_IMPORTER_URL', 'http://import.disqus.com/'); -} -define('DISQUS_URL', 'http://' . DISQUS_DOMAIN . '/'); -define('DISQUS_MEDIA_URL', 'http://' . DISQUS_DOMAIN . '/media/'); -define('DISQUS_API_URL', 'http://' . DISQUS_DOMAIN . '/api/'); +define('DISQUS_DOMAIN', 'disqus.com'); +define('DISQUS_IMPORTER_URL', 'https://import.disqus.com/'); +define('DISQUS_API_URL', 'https://disqus.com/api/'); define('DISQUS_RSS_PATH', '/latest.rss'); define('DISQUS_CAN_EXPORT', is_file(dirname(__FILE__) . '/export.php')); if (!defined('DISQUS_DEBUG')) { define('DISQUS_DEBUG', false); } -define('DISQUS_VERSION', '2.74'); +define('DISQUS_VERSION', '2.86'); define('DISQUS_SYNC_TIMEOUT', 30); /** - * Returns an array of all option identifiers used by DISQUS. + * Returns an array of all option identifiers used by Disqus. * @return array[int]string */ function dsq_options() { @@ -49,12 +36,12 @@ function dsq_options() { 'disqus_user_api_key', 'disqus_replace', 'disqus_cc_fix', + 'dsq_external_js', # SSO features 'disqus_partner_key', 'disqus_public_key', 'disqus_secret_key', 'disqus_sso_button', - 'disqus_sso_icon', # disables automatic sync via cron 'disqus_manual_sync', # disables server side rendering @@ -85,15 +72,10 @@ function dsq_plugin_basename($file) { return !empty($pieces[count($pieces)-1]) ? $pieces[count($pieces)-1] : $pieces[count($pieces)-2]; } -if ( !defined('WP_CONTENT_URL') ) { - define('WP_CONTENT_URL', get_option('siteurl') . '/wp-content'); -} if ( !defined('PLUGINDIR') ) { define('PLUGINDIR', 'wp-content/plugins'); // Relative to ABSPATH. For back compat. } -define('DSQ_PLUGIN_URL', WP_CONTENT_URL . '/plugins/' . dsq_plugin_basename(__FILE__)); - $mt_disqus_version = '2.01'; /** * Response from Disqus get_thread API call for comments template. @@ -111,7 +93,7 @@ function dsq_plugin_basename($file) { $dsq_api = new DisqusWordPressAPI(get_option('disqus_forum_url'), get_option('disqus_api_key')); /** - * DISQUS currently unsupported dev toggle to output comments for this query. + * Disqus currently unsupported dev toggle to output comments for this query. * * @global bool $DSQ_QUERY_COMMENTS * @since ? @@ -119,23 +101,120 @@ function dsq_plugin_basename($file) { $DSQ_QUERY_COMMENTS = false; /** - * DISQUS array to store post_ids from WP_Query for comment JS output. + * Disqus array to store post_ids from WP_Query for comment JS output. * * @global array $DSQ_QUERY_POST_IDS * @since 2.2 */ $DSQ_QUERY_POST_IDS = array(); +/** + * Admin scripts + */ + +add_action('wp_dashboard_setup', 'dsq_wp_dashboard_setup'); +add_action( 'admin_enqueue_scripts', 'load_admin_scripts' ); + +function load_admin_scripts($hook) { + + // Only show the pointer when Disqus isn't already configured + if ( dsq_is_installed() === false ) { + add_action( 'admin_print_footer_scripts', 'load_pointer_script_style' ); + } + + // Only load these scripts on the Disqus admin page + if ( 'comments_page_disqus' != $hook ) { + return; + } + + $admin_vars = array( + 'indexUrl' => admin_url('index.php'), + ); + + wp_register_script( 'admin_script', plugins_url( '/media/js/admin.js', __FILE__ ) ); + wp_localize_script( 'admin_script', 'adminVars', $admin_vars ); + wp_enqueue_script( 'admin_script', plugins_url( '/media/js/admin.js', __FILE__ ), array( 'jQuery') ); + + wp_register_script( 'upload_script', plugins_url( '/media/js/upload.js', __FILE__) ); + wp_enqueue_script( 'upload_script', plugins_url( '/media/js/upload.js', __FILE__), array( 'jQuery') ); +} + +function dsq_wp_dashboard_setup() { + add_action('admin_enqueue_scripts', 'load_dashboard_scripts'); +} + +function load_dashboard_scripts() { + $stats = get_dash_comment_counts(); + $dashboard_vars = array( + 'stats' => array( + 'totalComments' => number_format($stats->total_comments), + 'approved' => number_format($stats->approved), + 'moderated' => number_format($stats->moderated), + 'spam' => number_format($stats->spam), + ), + ); + + wp_register_script( 'dashboard_script', plugins_url( '/media/js/dashboard.js', __FILE__ ) ); + wp_localize_script( 'dashboard_script', 'dashboardVars', $dashboard_vars ); + wp_enqueue_script( 'dashboard_script', plugins_url( '/media/js/dashboard.js', __FILE__ ), array( 'jQuery') ); +} + +/** + * Adds a simple WordPress pointer to Comments menu, to remind the user to configure the plugin + */ +function load_pointer_script_style() { + + // Assume pointer shouldn't be shown + $enqueue_pointer_script_style = false; + + // Get array list of dismissed pointers for current user and convert it to array + $dismissed_pointers = explode( ',', get_user_meta( get_current_user_id(), 'dismissed_wp_pointers', true ) ); + + // Check if our pointer is not among dismissed ones + if( !in_array( 'disqus_settings_pointer', $dismissed_pointers ) ) { + $enqueue_pointer_script_style = true; + + // Add footer scripts using callback function + $pointer_content = '

'.dsq_i('Disqus needs to be configured').'

'; + $pointer_content .= '

'.dsq_i('Configure Disqus by clicking Comments to the left.').'

'; + + wp_register_script( 'pointer_script', plugins_url( '/media/js/pointer.js', __FILE__ ) ); + wp_localize_script( 'pointer_script', 'pointerContent', $pointer_content ); + wp_enqueue_script( 'pointer_script', plugins_url( '/media/js/pointer.js', __FILE__ ), array( 'jQuery') ); + } + + // Enqueue pointer CSS and JS files, if needed + if( $enqueue_pointer_script_style ) { + wp_enqueue_style( 'wp-pointer' ); + wp_enqueue_script( 'wp-pointer' ); + } +} + /** * Helper functions. */ +/** + * Tests if site is running on Wordpress VIP + * @return bool + */ +function is_wp_vip() { + return defined( 'WPCOM_IS_VIP_ENV' ) && WPCOM_IS_VIP_ENV; +} + /** * Tests if required options are configured to display the Disqus embed. * @return bool */ function dsq_is_installed() { - return get_option('disqus_forum_url') && get_option('disqus_api_key'); + $disqus_forum_url = get_option('disqus_forum_url'); + $disqus_api_key = get_option('disqus_api_key'); + if ( strlen( $disqus_forum_url ) > 0 && strlen( $disqus_api_key ) > 0 ) { + return true; + } + else { + return false; + } } /** @@ -149,6 +228,7 @@ function dsq_can_replace() { $replace = get_option('disqus_replace'); if ( is_feed() ) { return false; } + if ( !isset($post) ) { return false; } if ( 'draft' == $post->post_status ) { return false; } if ( !get_option('disqus_forum_url') ) { return false; } else if ( 'all' == $replace ) { return true; } @@ -190,11 +270,15 @@ function dsq_manage_dialog($message, $error = false) { . 'class="updated fade' . ( (version_compare($wp_version, '2.5', '<') && $error) ? '-ff0000' : '' ) . '">

' - . $message + . esc_attr($message) . '

'; } function dsq_sync_comments($comments) { + if ( count($comments) < 1 ) { + return; + } + global $wpdb; // user MUST be logged out during this process @@ -205,9 +289,23 @@ function dsq_sync_comments($comments) { foreach ( $comments as $comment ) { $thread_map[$comment->thread->id] = null; } - $thread_ids = "'" . implode("', '", array_keys($thread_map)) . "'"; - $results = $wpdb->get_results( "SELECT post_id, meta_value FROM $wpdb->postmeta WHERE meta_key = 'dsq_thread_id' AND meta_value IN ({$thread_ids}) LIMIT 1"); + $thread_ids = array_keys($thread_map); + + $threads_query = implode(', ', array_fill(0, count($thread_ids), '%s')); + + // add as many placeholders as needed + $sql = " + SELECT post_id, meta_value + FROM $wpdb->postmeta + WHERE meta_key = 'dsq_thread_id' AND meta_value IN (" . $threads_query . ") + "; + + // Call $wpdb->prepare passing the values of the array as separate arguments + $query = call_user_func_array(array($wpdb, 'prepare'), array_merge(array($sql), $thread_ids)); + + $results = $wpdb->get_results($query); + foreach ( $results as $result ) { $thread_map[$result->meta_value] = $result->post_id; } @@ -221,7 +319,8 @@ function dsq_sync_comments($comments) { // we know identifier starts with post_ID if ($post_ID = (int)substr($identifier, 0, strpos($identifier, ' '))) { $thread_map[$comment->thread->id] = $post_ID; - update_post_meta($post_ID, 'dsq_thread_id', $comment->thread->id); + $cleaned_thread_id = sanitize_meta( 'dsq_thread_id', $comment->thread->id, 'post' ); + update_post_meta($post_ID, 'dsq_thread_id', $cleaned_thread_id); if (DISQUS_DEBUG) { echo "updated post {$post_ID}: dsq_thread_id set to {$comment->thread->id}\n"; } @@ -282,7 +381,7 @@ function dsq_sync_comments($comments) { // and follow up using legacy Disqus agent if (!$commentdata) { - $commentdata = $wpdb->get_row($wpdb->prepare( "SELECT comment_ID, comment_parent FROM $wpdb->comments WHERE comment_agent = 'Disqus/1.0:{$comment->id}' LIMIT 1"), ARRAY_A); + $commentdata = $wpdb->get_row($wpdb->prepare( "SELECT comment_ID, comment_parent FROM $wpdb->comments WHERE comment_agent = %s LIMIT 1", 'Disqus/1.0:'.$comment->id), ARRAY_A); } if (!$commentdata) { // Comment doesnt exist yet, lets insert it @@ -339,7 +438,7 @@ function dsq_sync_comments($comments) { echo "inserted {$comment->id}: id is {$commentdata[comment_ID]}\n"; } } - if (!$commentdata['comment_parent'] && $comment->parent_post) { + if ((isset($commentdata['comment_parent']) && !$commentdata['comment_parent']) && $comment->parent_post) { $parent_id = $wpdb->get_var($wpdb->prepare( "SELECT comment_id FROM $wpdb->commentmeta WHERE meta_key = 'dsq_post_id' AND meta_value = %s LIMIT 1", $comment->parent_post)); if ($parent_id) { $wpdb->query($wpdb->prepare( "UPDATE $wpdb->comments SET comment_parent = %s WHERE comment_id = %s", $parent_id, $commentdata['comment_ID'])); @@ -412,63 +511,93 @@ function dsq_request_handler() { } } else { $ts = time() + 300; - wp_schedule_single_event($ts, 'dsq_sync_forum'); + $next_scheduled = wp_next_scheduled('dsq_sync_forum'); + if($next_scheduled) { + // error_log("Not scheduling dsq_sync_forum because it's already scheduled for " . $next_scheduled); + } else { + // error_log("Scheduling for $ts because dsq_sync_forum is not currently scheduled."); + wp_schedule_single_event($ts, 'dsq_sync_forum'); + } die('// sync scheduled'); } break; case 'export_comments': if (current_user_can('manage_options') && DISQUS_CAN_EXPORT) { + $msg = ''; + $result = ''; + $response = null; + $timestamp = intval($_GET['timestamp']); $post_id = intval($_GET['post_id']); - global $wpdb, $dsq_api; - $post = $wpdb->get_results($wpdb->prepare(" - SELECT * - FROM $wpdb->posts - WHERE post_type != 'revision' - AND post_status = 'publish' - AND comment_count > 0 - AND ID > %d - ORDER BY ID ASC - LIMIT 1 - ", $post_id)); - $post = $post[0]; - $post_id = $post->ID; - $max_post_id = $wpdb->get_var($wpdb->prepare(" - SELECT MAX(ID) - FROM $wpdb->posts - WHERE post_type != 'revision' - AND post_status = 'publish' - AND comment_count > 0 - ", $post_id)); - $eof = (int)($post_id == $max_post_id); - if ($eof) { - $status = 'complete'; - $msg = dsq_i('Your comments have been sent to Disqus and queued for import!
See the status of your import at Disqus'); + if ( isset($_GET['_dsqexport_wpnonce']) === false ) { + $msg = dsq_i('Unable to export comments. Make sure you are accessing this page from the Wordpress dashboard.'); + $result = 'fail'; } else { - $status = 'partial'; - $msg = dsq_i('Processed comments on post #%s…', $post_id); - } - $result = 'fail'; - $response = null; - if ($post) { - require_once(dirname(__FILE__) . '/export.php'); - $wxr = dsq_export_wp($post); - $response = $dsq_api->import_wordpress_comments($wxr, $timestamp, $eof); - if (!($response['group_id'] > 0)) { - $result = 'fail'; - $msg = '

'. dsq_i('Sorry, something unexpected happened with the export. Please try again

If your API key has changed, you may need to reinstall Disqus (deactivate the plugin and then reactivate it). If you are still having issues, refer to the WordPress help page.', 'http://disqus.com/help/wordpress'). '

'; - $response = $dsq_api->get_last_error(); + + // Check nonce + check_admin_referer('dsq-wpnonce_export', '_dsqexport_wpnonce'); + + global $wpdb, $dsq_api; + $post = $wpdb->get_results($wpdb->prepare(" + SELECT * + FROM $wpdb->posts + WHERE post_type != 'revision' + AND post_status = 'publish' + AND comment_count > 0 + AND ID > %d + ORDER BY ID ASC + LIMIT 1 + ", $post_id)); + $post = $post[0]; + $post_id = $post->ID; + $max_post_id = $wpdb->get_var(" + SELECT MAX(Id) + FROM $wpdb->posts + WHERE post_type != 'revision' + AND post_status = 'publish' + AND comment_count > 0 + "); + $eof = (int)($post_id == $max_post_id); + if ($eof) { + $status = 'complete'; + $msg = dsq_i('Your comments have been sent to Disqus and queued for import!'); + $msg .= '
'; + $msg .= dsq_i('See the status of your import at Disqus') . ''; } else { - if ($eof) { - $msg = dsq_i('Your comments have been sent to Disqus and queued for import!
See the status of your import at Disqus', $response['link']); - + $status = 'partial'; + $msg = dsq_i('Processed comments on post') . ' #'. $post_id . '…'; + } + $result = 'fail'; + if ($post) { + require_once(dirname(__FILE__) . '/export.php'); + $wxr = dsq_export_wp($post); + $response = $dsq_api->import_wordpress_comments($wxr, $timestamp, $eof); + if (!($response['group_id'] > 0)) { + $result = 'fail'; + $msg = '

'; + $msg .= dsq_i('Sorry, something unexpected happened with the export. Please try again.'); + $msg .= '

'; + $msg .= dsq_i('If your API key has changed, you may need to reinstall Disqus (deactivate the plugin and then reactivate it).'); + $msg .= dsq_i('If you are still having issues, refer to the %s WordPress help page', + ''); + $msg .= '

'; + $response = $dsq_api->get_last_error(); + } + else { + if ($eof) { + $msg = dsq_i('Your comments have been sent to Disqus and queued for import!'); + $msg .= '
'; + $msg .= dsq_i('See the status of your import at Disqus'); + $msg .= ''; + } + $result = 'success'; } - $result = 'success'; } } -// send AJAX response + + // send AJAX response $response = compact('result', 'timestamp', 'status', 'post_id', 'msg', 'eof', 'response'); header('Content-type: text/javascript'); echo cf_json_encode($response); @@ -477,38 +606,52 @@ function dsq_request_handler() { break; case 'import_comments': if (current_user_can('manage_options')) { - if (!isset($_GET['last_comment_id'])) $last_comment_id = false; - else $last_comment_id = $_GET['last_comment_id']; + $msg = ''; + $result = ''; + $response = null; - if ($_GET['wipe'] == '1') { - $wpdb->query("DELETE FROM `".$wpdb->prefix."commentmeta` WHERE meta_key IN ('dsq_post_id', 'dsq_parent_post_id')"); - $wpdb->query("DELETE FROM `".$wpdb->prefix."comments` WHERE comment_agent LIKE 'Disqus/%%'"); + if ( isset($_GET['_dsqimport_wpnonce']) === false ) { + $msg = dsq_i('Unable to import comments. Make sure you are accessing this page from the Wordpress dashboard.'); + $result = 'fail'; } + else + { + // Check nonce + check_admin_referer('dsq-wpnonce_import', '_dsqimport_wpnonce'); - ob_start(); - $response = dsq_sync_forum($last_comment_id, true); - $debug = ob_get_clean(); - if (!$response) { - $status = 'error'; - $result = 'fail'; - $error = $dsq_api->get_last_error(); - $msg = '

'.dsq_i('There was an error downloading your comments from Disqus.').'
'.htmlspecialchars($error).'

'; - } else { - list($comments, $last_comment_id) = $response; - if (!$comments) { - $status = 'complete'; - $msg = dsq_i('Your comments have been downloaded from Disqus and saved in your local database.'); + if (!isset($_GET['last_comment_id'])) $last_comment_id = false; + else $last_comment_id = $_GET['last_comment_id']; + + if ($_GET['wipe'] == '1') { + $wpdb->query("DELETE FROM `".$wpdb->prefix."commentmeta` WHERE meta_key IN ('dsq_post_id', 'dsq_parent_post_id')"); + $wpdb->query("DELETE FROM `".$wpdb->prefix."comments` WHERE comment_agent LIKE 'Disqus/%%'"); + } + + ob_start(); + $response = dsq_sync_forum($last_comment_id, true); + $debug = ob_get_clean(); + if (!$response) { + $status = 'error'; + $result = 'fail'; + $error = $dsq_api->get_last_error(); + $msg = '

'.dsq_i('There was an error downloading your comments from Disqus.').'
'.esc_attr($error).'

'; } else { - $status = 'partial'; - $msg = dsq_i('Import in progress (last post id: %s) …', $last_comment_id); + list($comments, $last_comment_id) = $response; + if (!$comments) { + $status = 'complete'; + $msg = dsq_i('Your comments have been downloaded from Disqus and saved in your local database.'); + } else { + $status = 'partial'; + $msg = dsq_i('Import in progress (last post id: %s)', $last_comment_id) . ' …'; + } + $result = 'success'; } - $result = 'success'; + $debug = explode("\n", $debug); + $response = compact('result', 'status', 'comments', 'msg', 'last_comment_id', 'debug'); + header('Content-type: text/javascript'); + echo cf_json_encode($response); + die(); } - $debug = explode("\n", $debug); - $response = compact('result', 'status', 'comments', 'msg', 'last_comment_id', 'debug'); - header('Content-type: text/javascript'); - echo cf_json_encode($response); - die(); } break; } @@ -531,7 +674,7 @@ function dsq_image_upload_handler($option_name) { // If the uploaded file is the right format if(in_array($uploaded_file_type, $allowed_file_types)) { // Options array for the wp_handle_upload function. 'test_upload' => false - $upload_overrides = array( 'test_form' => false ); + $upload_overrides = array( 'test_form' => false ); // Handle the upload using WP's wp_handle_upload function. Takes the posted file and an options array $uploaded_file = wp_handle_upload($_FILES[$option_name], $upload_overrides); // If the wp_handle_upload call returned a local path for the image @@ -558,10 +701,24 @@ function dsq_get_pending_post_ids() { } function dsq_clear_pending_post_ids($post_ids) { + if ( count($post_ids) < 1 ) { + return; + } + global $wpdb; - $post_ids_query = "'" . implode("', '", $post_ids) . "'"; - $wpdb->query("DELETE FROM {$wpdb->postmeta} WHERE meta_key = 'dsq_needs_sync' AND post_id IN ({$post_ids_query})"); + $posts_query = implode(', ', array_fill(0, count($post_ids), '%s')); + + // add as many placeholders as needed + $sql = " + DELETE FROM {$wpdb->postmeta} + WHERE meta_key = 'dsq_needs_sync' AND post_id IN (" . $posts_query . ") + "; + + // Call $wpdb->prepare passing the values of the array as separate arguments + $query = call_user_func_array(array($wpdb, 'prepare'), array_merge(array($sql), $post_ids)); + + $wpdb->query($query); update_meta_cache('dsq_needs_sync', $post_ids); } @@ -579,7 +736,7 @@ function dsq_sync_post($post_id) { function dsq_sync_forum($last_comment_id=false, $force=false) { global $dsq_api, $wpdb; - set_time_limit(DISQUS_SYNC_TIMEOUT); + set_time_limit(apply_filters('disqus_sync_timeout', DISQUS_SYNC_TIMEOUT)); if ($force) { $sync_time = null; @@ -653,7 +810,11 @@ function dsq_update_permalink($post) { 'url' => dsq_link_for_post($post) )); - update_post_meta($post->ID, 'dsq_thread_id', $response->id); + //Make sure that response exists so that warnings are not thrown + if (! empty($response)) { + $cleaned_thread_id = sanitize_meta( 'dsq_thread_id', $response->id, 'post' ); + update_post_meta($post->ID, 'dsq_thread_id', $cleaned_thread_id); + } return $response; } @@ -710,7 +871,7 @@ function _wp_specialchars( $string, $quote_style = ENT_NOQUOTES, $charset = fals $string = preg_replace( '/&(#?x?[0-9a-z]+);/i', '|wp_entity|$1|/wp_entity|', $string ); } - $string = @htmlspecialchars( $string, $quote_style, $charset ); + $string = @esc_attr( $string, $quote_style, $charset ); // Handle double encoding ourselves if ( !$double_encode ) { @@ -817,7 +978,7 @@ function dsq_comment( $comment, $args, $depth ) {
  • id="dsq-comment-">
    - + @@ -834,7 +995,7 @@ function dsq_comment( $comment, $args, $depth ) { case 'trackback' : ?>
  • -

    +

    ()

  • '.$comment_text.''; + return ''.$comment_text.''; } else { return $comment_text; } @@ -861,7 +1022,7 @@ function dsq_comments_text($comment_text) { function dsq_bloginfo_url($url) { if ( get_feed_link('comments_rss2') == $url && dsq_can_replace() ) { - return 'http://' . strtolower(get_option('disqus_forum_url')) . '.' . DISQUS_DOMAIN . DISQUS_RSS_PATH; + return 'https://' . strtolower(get_option('disqus_forum_url')) . '.disqus.com' . DISQUS_RSS_PATH; } else { return $url; } @@ -873,7 +1034,7 @@ function dsq_plugin_action_links($links, $file) { if (!dsq_is_installed()) { $settings_link = ''.dsq_i('Configure').''; } else { - $settings_link = ''.dsq_i('Settings').''; + $settings_link = ''.dsq_i('Settings').''; } array_unshift($links, $settings_link); } @@ -905,24 +1066,8 @@ function dsq_add_pages() { } add_action('admin_menu', 'dsq_add_pages', 10); -// a little jQuery goodness to get comments menu working as desired -function dsq_menu_admin_head() { -?> - -get_results(" @@ -946,28 +1091,15 @@ function dsq_dash_comment_counts() { if ( empty($stats[$key]) ) $stats[$key] = 0; } - $stats = (object) $stats; -?> - - - +' type='text/css' /> - "; + echo ""; } } } @@ -1151,84 +1183,50 @@ function dsq_add_query_posts($posts) { } } -// check to see if the posts in the loop match the original request or an explicit request, if so output the JS -function dsq_loop_end($query) { - if ( get_option('disqus_cc_fix') == '1' || !count($query->posts) || is_single() || is_page() || is_feed() || !dsq_can_replace() ) { - return; - } - global $DSQ_QUERY_POST_IDS; - foreach ($query->posts as $post) { - $loop_ids[] = intval($post->ID); - } - $posts_key = md5(serialize($loop_ids)); - if (isset($DSQ_QUERY_POST_IDS[$posts_key])) { - dsq_output_loop_comment_js($DSQ_QUERY_POST_IDS[$posts_key]); - } -} -add_action('loop_end', 'dsq_loop_end'); - -// if someone has a better hack, let me know -// prevents duplicate calls to count.js -$_HAS_COUNTS = false; +function dsq_output_count_js() { + if ( get_option('dsq_external_js') == '1' ) { + $count_vars = array( + 'disqusShortname' => strtolower( get_option( 'disqus_forum_url' ) ), + ); -function dsq_output_loop_comment_js($post_ids = null) { - global $_HAS_COUNTS; - if ($_HAS_COUNTS) return; - $_HAS_COUNTS = true; - if (count($post_ids)) { -?> - - + + - -post_status != 'publish') { return; } @@ -1248,7 +1246,9 @@ function dsq_prev_permalink($post_id) { function dsq_check_permalink($post_id) { global $dsq_prev_permalinks; - if (!empty($dsq_prev_permalinks['post_'.$post_id]) && $dsq_prev_permalinks['post_'.$post_id] != get_permalink($post_id)) { + if (!empty($dsq_prev_permalinks['post_'.$post_id]) && + $dsq_prev_permalinks['post_'.$post_id] != get_permalink($post_id) + ) { $post = get_post($post_id); dsq_update_permalink($post); } @@ -1269,10 +1269,9 @@ function dsq_check_permalink($post_id) { */ if(!function_exists('cf_json_encode')) { function cf_json_encode($data) { -// json_encode is sending an application/x-javascript header on Joyent servers -// for some unknown reason. -// if(function_exists('json_encode')) { return json_encode($data); } -// else { return cfjson_encode($data); } + + // json_encode is sending an application/x-javascript header on Joyent servers + // for some unknown reason. return cfjson_encode($data); } @@ -1355,6 +1354,22 @@ function cfjson_encode($arr) { // Single Sign-on Integration +function dsq_sso_login() { + global $current_site; + $sitename = get_bloginfo('name'); + $siteurl = site_url(); + $button = get_option('disqus_sso_button'); + $sso_login_str = 'this.sso = { + name: "' . esc_js( $sitename ) . '", + button: "' . $button . '", + url: "' . $siteurl . '/wp-login.php", + logout: "' . $siteurl . '/wp-login.php?action=logout", + width: "800", + height: "700" + };'; + return $sso_login_str; +} + function dsq_sso() { if ($key = get_option('disqus_partner_key')) { // use old style SSO @@ -1397,24 +1412,6 @@ function dsq_sso() { } } -function dsq_sso_login() { - global $current_site; - $sitename = get_bloginfo('name'); - $siteurl = site_url(); - $button = get_option('disqus_sso_button'); - $icon = get_option('disqus_sso_icon'); - $sso_login_str = 'this.sso = { - name: "'.wp_specialchars_decode($sitename, ENT_QUOTES).'", - button: "'.$button.'", - icon: "'.$icon.'", - url: "'.$siteurl.'/wp-login.php", - logout: "'.$siteurl.'/wp-login.php?action=logout", - width: "800", - height: "700" - }'; - return $sso_login_str; -} - // from: http://www.php.net/manual/en/function.sha1.php#39492 // Calculate HMAC-SHA1 according to RFC2104 // http://www.ietf.org/rfc/rfc2104.txt @@ -1482,89 +1479,28 @@ function dsq_install($allow_database_install=true) { // if this is a new install, we should not set disqus active if ($version == '0') { - add_option('disqus_active', 0); + add_option('disqus_active', '0'); } else { - add_option('disqus_active', 1); + add_option('disqus_active', '1'); } update_option('disqus_version', DISQUS_VERSION); } -/** - * Adds a simple WordPress pointer to Comments menu, to remind the user to configure the plugin - */ -function dsq_enqueue_pointer_script_style( $hook_suffix ) { - - // Assume pointer shouldn't be shown - $enqueue_pointer_script_style = false; - - // Get array list of dismissed pointers for current user and convert it to array - $dismissed_pointers = explode( ',', get_user_meta( get_current_user_id(), 'dismissed_wp_pointers', true ) ); - - // Check if our pointer is not among dismissed ones - if( !in_array( 'disqus_settings_pointer', $dismissed_pointers ) ) { - $enqueue_pointer_script_style = true; - - // Add footer scripts using callback function - add_action( 'admin_print_footer_scripts', 'dsq_pointer_print_scripts' ); - } - - // Enqueue pointer CSS and JS files, if needed - if( $enqueue_pointer_script_style ) { - wp_enqueue_style( 'wp-pointer' ); - wp_enqueue_script( 'wp-pointer' ); - } - -} -if (!dsq_is_installed()) { - // Only show the pointer when Disqus isn't already configured - add_action( 'admin_enqueue_scripts', 'dsq_enqueue_pointer_script_style' ); -} - -function dsq_pointer_print_scripts() { - - $pointer_content = '

    DISQUS needs to be configured

    '; - $pointer_content .= '

    Configure DISQUS by clicking Comments to the left.

    '; -?> - - - -query("CREATE INDEX disqus_dupecheck ON `".$wpdb->prefix."commentmeta` (meta_key, meta_value(11));"); } } function dsq_reset_database($version=0) { global $wpdb; - - if (version_compare($version, '2.49', '>=')) { + + if ( version_compare($version, '2.49', '>=') && !is_wp_vip() ) { $wpdb->query("DROP INDEX disqus_dupecheck ON `".$wpdb->prefix."commentmeta`;"); } } diff --git a/disqus/export.php b/disqus/export.php index 7f8aa59..b31b630 100644 --- a/disqus/export.php +++ b/disqus/export.php @@ -3,8 +3,9 @@ * Adapted from WordPress 2.8 */ @set_time_limit(0); -@ini_set('memory_limit', '256M'); define('WXR_VERSION', '1.0'); +define('DISQUS_MEMORY_LIMIT', '256M'); +@ini_set('memory_limit', apply_filters('disqus_memory_limit', DISQUS_MEMORY_LIMIT)); /** * {@internal Missing Short Description}} @@ -139,7 +140,7 @@ function dsq_export_wp($post, $comments=null) { + * @copyright 2007-2016 Big Head Labs + * @link https://disqus.com/ + * @package Disqus + * @version 1.1 + */ + +require_once(dirname(__FILE__) . '/url.php'); + +/** @#+ + * Constants + */ +/** + * Base URL for Disqus. + */ + +define('DISQUS_TYPE_SPAM', 'spam'); +define('DISQUS_TYPE_DELETED', 'killed'); +define('DISQUS_TYPE_KILLED', DISQUS_TYPE_DELETED); +define('DISQUS_TYPE_NEW', 'new'); + +define('DISQUS_STATE_APPROVED', 'approved'); +define('DISQUS_STATE_UNAPPROVED', 'unapproved'); +define('DISQUS_STATE_SPAM', 'spam'); +define('DISQUS_STATE_DELETED', 'killed'); +define('DISQUS_STATE_KILLED', DISQUS_STATE_DELETED); + +define('DISQUS_ACTION_SPAM', 'spam'); +define('DISQUS_ACTION_APPROVE', 'approve'); +define('DISQUS_ACTION_DELETE', 'delete'); +define('DISQUS_ACTION_KILL', 'kill'); + +if (!extension_loaded('json')) { + require_once(dirname(__FILE__) . '/json.php'); + function dsq_json_decode($data) { + $json = new JSON; + return $json->unserialize($data); + } +} else { + function dsq_json_decode($data) { + return json_decode($data); + } +} + +/** + * Helper methods for all of the Disqus 1.1 API methods. + * + * @package Disqus + * @author DISQUS.com + * @copyright 2007-2016 Big Head Labs + * @version 1.1 + */ +class DisqusAPI { + var $user_api_key; + var $forum_api_key; + var $api_url = 'https://disqus.com/api/'; + var $api_version = '1.1'; + + /** + * Creates a new interface to the Disqus API. + * + * @param $user_api_key + * (optional) The User API key to use. + * @param $forum_api_key + * (optional) The Forum API key to use. + * @param $api_url + * (optional) The prefix URL to use when calling the Disqus API. + */ + function __construct($user_api_key, $forum_api_key, $api_url='https://disqus.com/api/') { + $this->user_api_key = $user_api_key; + $this->forum_api_key = $forum_api_key; + $this->api_url = $api_url; + $this->last_error = null; + } + + /** + * Makes a call to a Disqus API method. + * + * @return + * The Disqus object. + * @param $method + * The Disqus API method to call. + * @param $args + * An associative array of arguments to be passed. + * @param $post + * TRUE or FALSE, depending on whether we're making a POST call. + */ + function call($method, $args=array(), $post=false) { + $url = $this->api_url . $method . '/'; + + if (!isset($args['user_api_key'])) { + $args['user_api_key'] = $this->user_api_key; + } + if (!isset($args['forum_api_key'])) { + $args['forum_api_key'] = $this->forum_api_key; + } + if (!isset($args['api_version'])) { + $args['api_version'] = $this->api_version; + } + + foreach ($args as $key=>$value) { + // XXX: Disqus is lacking some exception handling and we sometimes + // end up with 500s when passing invalid values + if (empty($value)) unset($args[$key]); + } + + if (!$post) { + $url .= '?' . dsq_get_query_string($args); + $args = null; + } + + if (!($response = dsq_urlopen($url, $args)) || !$response['code']) { + $this->last_error = 'Unable to connect to the Disqus API servers'; + return false; + } + + if ($response['code'] != 200) { + if ($response['code'] == 500) { + // Try to grab the exception ID for better reporting + if (!empty($response['headers']['X-Sentry-ID'])) { + $this->last_error = 'DISQUS returned a bad response (HTTP '.$response['code'].', ReferenceID: '.$response['headers']['X-Sentry-ID'].')'; + return false; + } + } elseif ($response['code'] == 400) { + $data = dsq_json_decode($response['data']); + if ($data && $data->message) { + $this->last_error = $data->message; + } else { + $this->last_error = "DISQUS returned a bad response (HTTP ".$response['code'].")"; + } + return false; + } + $this->last_error = "DISQUS returned a bad response (HTTP ".$response['code'].")"; + return false; + } + + $data = dsq_json_decode($response['data']); + + if (!$data) { + $this->last_error = 'No valid JSON content returned from Disqus'; + return false; + } + + if (!$data->succeeded) { + if (!$data->message) { + $this->last_error = '(No error message was received)'; + } else { + $this->last_error = $data->message; + } + return false; + } + + $this->last_error = null; + + return $data->message; + } + + /** + * Retrieve the last error message recorded. + * + * @return + * The last recorded error from the API + */ + function get_last_error() { + if (empty($this->last_error)) return; + if (!is_string($this->last_error)) { + return var_export($this->last_error); + } + return $this->last_error; + } + + /** + * Validate API key and get username. + * + * @return + * Username matching the API key + */ + function get_user_name() { + return $this->call('get_user_name', array(), true); + } + + /** + * Returns an array of hashes representing all forums the user owns. + * + * @return + * An array of hashes representing all forums the user owns. + */ + function get_forum_list() { + return $this->call('get_forum_list'); + } + + /** + * Get a forum API key for a specific forum. + * + * @param $forum_id + * the unique id of the forum + * @return + * A string which is the Forum Key for the given forum. + */ + function get_forum_api_key($forum_id) { + $params = array( + 'forum_id' => $forum_id, + ); + + return $this->call('get_forum_api_key', $params); + } + + /** + * Get a list of comments on a website. + * + * Both filter and exclude are multivalue arguments with comma as a divider. + * That makes is possible to use combined requests. For example, if you want + * to get all deleted spam messages, your filter argument should contain + * 'spam,killed' string. + * + * @param $forum_id + * The forum ID. + * @param $params + * - limit: Number of entries that should be included in the response. Default is 25. + * - start: Starting point for the query. Default is 0. + * - filter: Type of entries that should be returned. + * - exclude: Type of entries that should be excluded from the response. + * @return + * Returns posts from a forum specified by id. + */ + function get_forum_posts($forum_id, $params=array()) { + $params['forum_id'] = $forum_id; + + return $this->call('get_forum_posts', $params); + } + + /** + * Count a number of comments in articles. + * + * @param $thread_ids + * an array of thread IDs belonging to the given forum. + * @return + * A hash having thread_ids as keys and 2-element arrays as values. + */ + function get_num_posts($thread_ids) { + $params = array( + 'thread_ids' => is_array($thread_ids) ? implode(',', $thread_ids) : $thread_ids, + ); + + return $this->call('get_num_posts', $params); + } + + /** + * Returns a list of categories that were created for a website (forum) provided. + * + * @param $forum_id + * the unique of the forum + * @return + * A hash containing category_id, title, forum_id, and is_default. + */ + function get_categories_list($forum_id) { + $params = array( + 'forum_id' => $forum_id, + ); + + return $this->call('get_categories_list', $params); + } + + /** + * Get a list of threads on a website. + * + * @param $forum_id + * the unique id of the forum. + * @param $params + * - limit: Number of entries that should be included in the response. Default is 25. + * - start: Starting point for the query. Default is 0. + * - category_id: Filter entries by category + * @return + * An array of hashes representing all threads belonging to the given forum. + */ + function get_thread_list($forum_id, $params=array()) { + $params['forum_id'] = $forum_id; + + return $this->call('get_thread_list', $params); + } + + /** + * Get a list of threads with new comments. + * + * @param $forum_id + * The Forum ID. + * @param $since + * Start date for new posts. Format: 2009-03-30T15:41, Timezone: UTC. + * @return + * An array of hashes representing all threads with new comments since offset. + */ + function get_updated_threads($forum_id, $since) { + $params = array( + 'forum_id' => $forum_id, + 'since' => is_string($since) ? $string : strftime('%Y-%m-%dT%H:%M', $since), + ); + + return $this->call('get_updated_threads', $params); + } + + /** + * Get a list of comments in a thread. + * + * Both filter and exclude are multivalue arguments with comma as a divider. + * That makes is possible to use combined requests. For example, if you want + * to get all deleted spam messages, your filter argument should contain + * 'spam,killed' string. Note that values are joined by AND statement so + * 'spam,new' will return all messages that are new and marked as spam. It + * will not return messages that are new and not spam or that are spam but + * not new (i.e. has already been moderated). + * + * @param $thread_id + * The ID of a thread belonging to the given forum + * @param $params + * - limit: Number of entries that should be included in the response. Default is 25. + * - start: Starting point for the query. Default is 0. + * - filter: Type of entries that should be returned (new, spam or killed). + * - exclude: Type of entries that should be excluded from the response (new, spam or killed). + * @return + * An array of hashes representing representing all posts belonging to the + * given forum. + */ + function get_thread_posts($thread_id, $params=array()) { + $params['thread_id'] = $thread_id; + + return $this->call('get_thread_posts', $params); + } + + /** + * Get or create thread by identifier. + * + * This method tries to find a thread by its identifier and title. If there is + * no such thread, the method creates it. In either case, the output value is + * a thread object. + * + * @param $identifier + * Unique value (per forum) for a thread that is used to keep be able to get + * data even if permalink is changed. + * @param $title + * The title of the thread to possibly be created. + * @param $params + * - category_id: Filter entries by category + * - create_on_fail: if thread does not exist, the method will create it + * @return + * Returns a hash with two keys: + * - thread: a hash representing the thread corresponding to the identifier. + * - created: indicates whether the thread was created as a result of this + * method call. If created, it will have the specified title. + */ + function thread_by_identifier($identifier, $title, $params=array()) { + $params['identifier'] = $identifier; + $params['title'] = $title; + + return $this->call('thread_by_identifier', $params, true); + } + + /** + * Get thread by URL. + * + * Finds a thread by its URL. Output value is a thread object. + * + * @param $url + * the URL to check for an associated thread + * @param $partner_api_key + * (optional) The Partner API key. + * @return + * A thread object, otherwise NULL. + */ + function get_thread_by_url($url, $partner_api_key=null) { + $params = array( + 'url' => $url, + 'partner_api_key' => $partner_api_key, + ); + + return $this->call('get_thread_by_url', $params); + } + + /** + * Updates thread. + * + * Updates thread, specified by id and forum API key, with values described in + * the optional arguments. + * + * @param $thread_id + * the ID of a thread belonging to the given forum + * @param $params + * - title: the title of the thread + * - slug: the per-forum-unique string used for identifying this thread in + * disqus.com URL’s relating to this thread. Composed of + * underscore-separated alphanumeric strings. + * - url: the URL this thread is on, if known. + * - allow_comments: whether this thread is open to new comments + * @return + * Returns an empty success message. + */ + function update_thread($thread_id, $params=array()) { + $params['thread_id'] = $thread_id; + + return $this->call('update_thread', $params, true); + } + + /** + * Creates a new post. + * + * Creates a comment to the thread specified by id. + * + * @param $thread_id + * the thread to post to + * @param $message + * the content of the post + * @param $author_name + * the post creator’s name + * @param $author_email + * the post creator’s email address + * @param $params + * - partner_api_key + * - created_at: Format: 2009-03-30T15:41, Timezone: UTC + * - ip_address: the author’s IP address + * - author_url: the author's homepage + * - parent_post: the id of the parent post + * - state: Comment's state, must be one of the following: approved, + * unapproved, spam, killed + * @return + * Returns modified version. + */ + function create_post($thread_id, $message, $author_name, $author_email, $params=array()) { + $params['thread_id'] = $thread_id; + $params['message'] = $message; + $params['author_name'] = $author_name; + $params['author_email'] = $author_email; + + return $this->call('create_post', $params, true); + } + + /** + * Delete a comment or mark it as spam (or not spam). + * + * @param $post_id + * The Post ID. + * @param $action + * Name of action to be performed. Value can be 'spam', 'approve' or 'kill'. + * @return + * Returns modified version. + */ + function moderate_post($post_id, $action) { + $params = array( + 'post_id' => $post_id, + 'action' => $action, + ); + + return $this->call('moderate_post', $params, true); + } +} + +?> diff --git a/disqus/lib/api/disqus/json.php b/disqus/lib/api/disqus/json.php new file mode 100644 index 0000000..ed47bf5 --- /dev/null +++ b/disqus/lib/api/disqus/json.php @@ -0,0 +1,378 @@ + + * @copyright 2007 Cesar D. Rodas + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version 1.0 + * @link http://cesars.users.phpclasses.org/json + */ + +define('IN_NOWHERE',0); +define('IN_STRING',1); +define('IN_OBJECT',2); +define('IN_ATOMIC',3); +define('IN_ASSIGN',4); +define('IN_ENDSTMT',5); +define('IN_ARRAY',6); + +/** + * JSON + * + * This class serilize an PHP OBJECT or an ARRAY into JSON + * notation. Also convert a JSON text into a PHP OBJECT or + * array. + * + * @category Javascript + * @package JSON + * @author Cesar D. Rodas + * @copyright 2007 Cesar D. Rodas + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version 1.0 + * @link http://cesars.users.phpclasses.org/json + */ +class JSON +{ + /** + * Was parsed with an error? + * + * var bool + * @access private + */ + var $error; + + function __construct() { + $this->error = false; + } + + /** + * Serialize + * + * Serialize a PHP OBJECT or an ARRAY into + * JSON notation. + * + * param mixed $obj Object or array to serialize + * return string JSON. + */ + function serialize($obj) { + if ( is_object($obj) ) { + $e = get_object_vars($obj); + /* bug reported by Ben Rowe */ + /* Adding default empty array if the */ + /* object doesn't have any property */ + $properties = array(); + foreach ($e as $k => $v) { + $properties[] = $this->_serialize( $k,$v ); + } + return "{".implode(",",$properties)."}"; + } else if ( is_array($obj) ) { + return $this->_serialize('',$obj); + } + } + + /** + * UnSerialize + * + * Transform an JSON text into a PHP object + * and return it. + * @access public + * @param string $text JSON text + * @return mixed PHP Object, array or false. + */ + function unserialize( $text ) { + $this->error = false; + + return !$this->error ? $this->_unserialize($text) : false; + } + + /** + * UnSerialize + * + * Transform an JSON text into a PHP object + * and return it. + * @access private + * @param string $text JSON text + * @return mixed PHP Object, array or false. + */ + function _unserialize($text) { + $ret = new stdClass; + + while ( $f = $this->getNextToken($text,$i,$type) ) { + switch ( $type ) { + case IN_ARRAY: + $tmp = $this->_unserializeArray($text); + $ret = $tmp[0]; + break; + case IN_OBJECT: + $g=0; + do { + $varName = $this->getNextToken($f,$g,$xType); + if ( $xType != IN_STRING ) { + return false; /* error parsing */ + } + $this->getNextToken($f,$g,$xType); + if ( $xType != IN_ASSIGN) return false; + $value = $this->getNextToken($f,$g,$xType); + + if ( $xType == IN_OBJECT) { + $ret->$varName = $this->unserialize( "{".$value."}" ); + $g--; + } else if ($xType == IN_ARRAY) { + $ret->$varName = $this->_unserializeArray( $value); + $g--; + } else + $ret->$varName = $value; + + $this->getNextToken($f,$g,$xType); + } while ( $xType == IN_ENDSTMT); + break; + default: + $this->error = true; + break 2; + } + } + return $ret; + } + + /** + * JSON Array Parser + * + * This method transform an json-array into a PHP + * array + * @access private + * @param string $text String to parse + * @return Array PHP Array + */ + function _unserializeArray($text) { + $r = array(); + do { + $f = $this->getNextToken($text,$i,$type); + switch ( $type ) { + case IN_STRING: + case IN_ATOMIC: + $r[] = $f; + break; + case IN_OBJECT: + $r[] = $this->unserialize("{".$f."}"); + $i--; + break; + case IN_ARRAY: + $r[] = $this->_unserializeArray($f); + $i--; + break; + + } + $this->getNextToken($text,$i,$type); + } while ( $type == IN_ENDSTMT); + + return $r; + } + + /** + * Tokenizer + * + * Return to the Parser the next valid token and the type + * of the token. If the tokenizer fails it returns false. + * + * @access private + * @param string $e Text to extract token + * @param integer $i Start position to search next token + * @param integer $state Variable to get the token type + * @return string|bool Token in string or false on error. + */ + function getNextToken($e, &$i, &$state) { + $state = IN_NOWHERE; + $end = -1; + $start = -1; + while ( $i < strlen($e) && $end == -1 ) { + switch( $e[$i] ) { + /* objects */ + case "{": + case "[": + $_tag = $e[$i]; + $_endtag = $_tag == "{" ? "}" : "]"; + if ( $state == IN_NOWHERE ) { + $start = $i+1; + switch ($state) { + case IN_NOWHERE: + $aux = 1; /* for loop objects */ + $state = $_tag == "{" ? IN_OBJECT : IN_ARRAY; + break; + default: + break 2; /* exit from switch and while */ + } + while ( ++$i && $i < strlen($e) && $aux != 0 ) { + switch( $e[$i] ) { + case $_tag: + $aux++; + break; + case $_endtag: + $aux--; + break; + } + } + $end = $i-1; + } + break; + + case '"': + case "'": + $state = IN_STRING; + $buf = ""; + while ( ++$i && $i < strlen($e) && $e[$i] != '"' ) { + if ( $e[$i] == "\\") + $i++; + $buf .= $e[$i]; + } + $i++; + return $buf; + break; + case ":": + $state = IN_ASSIGN; + $end = 1; + break; + case "n": + if ( substr($e,$i,4) == "null" ) { + $i=$i+4; + $state = IN_ATOMIC; + return NULL; + } + else break 2; /* exit from switch and while */ + case "t": + if ( substr($e,$i,4) == "true") { + $state = IN_ATOMIC; + $i=$i+4; + return true; + } + else break 2; /* exit from switch and while */ + break; + case "f": + if ( substr($e,$i,5) == "false") { + $state = IN_ATOMIC; + $i=$i+5; + return false; + } + else break 2; /* exit from switch and while */ + break; + case ",": + $state = IN_ENDSTMT; + $end = 1; + break; + case " ": + case "\t": + case "\r": + case "\n": + break; + case "+": + case "-": + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case '.': + $state = IN_ATOMIC; + $start = (int)$i; + if ( $e[$i] == "-" || $e[$i] == "+") + $i++; + for ( ; $i < strlen($e) && (is_numeric($e[$i]) || $e[$i] == "." || strtolower($e[$i]) == "e") ;$i++){ + $n = $i+1 < strlen($e) ? $e[$i+1] : ""; + $a = strtolower($e[$i]); + if ( $a == "e" && ($n == "+" || $n == "-")) + $i++; + else if ( $a == "e") + $this->error=true; + } + + $end = $i; + break 2; /* break while too */ + default: + $this->error = true; + + } + $i++; + } + + return $start == -1 || $end == -1 ? false : substr($e, $start, $end - $start); + } + + /** + * Internal Serializer + * + * @param string $key Variable name + * @param mixed $value Value of the variable + * @access private + * @return string Serialized variable + */ + function _serialize ( $key = '', &$value ) { + $r = ''; + if ( $key != '')$r .= "\"${key}\" : "; + if ( is_numeric($value) ) { + $r .= ''.$value.''; + } else if ( is_string($value) ) { + $r .= '"'.$this->toString($value).'"'; + } else if ( is_object($value) ) { + $r .= $this->serialize($value); + } else if ( is_null($value) ) { + $r .= "null"; + } else if ( is_bool($value) ) { + $r .= $value ? "true":"false"; + } else if ( is_array($value) ) { + foreach($value as $k => $v) + $f[] = $this->_serialize('',$v); + $r .= "[".implode(",",$f)."]"; + unset($f); + } + return $r; + } + + /** + * Convert String variables + * + * @param string $e Variable with an string value + * @access private + * @return string Serialized variable + */ + function toString($e) { + $rep = array("\\","\r","\n","\t","'",'"'); + $val = array("\\\\",'\r','\n','\t','\'','\"'); + $e = str_replace($rep, $val, $e); + return $e; + } +} +?> \ No newline at end of file diff --git a/disqus/lib/api/disqus/url.php b/disqus/lib/api/disqus/url.php new file mode 100644 index 0000000..7db5385 --- /dev/null +++ b/disqus/lib/api/disqus/url.php @@ -0,0 +1,296 @@ +$value) { + $postdata_str .= urlencode($key) . '=' . urlencode($value) . '&'; + } + } + + return $postdata_str; +} + + +function dsq_get_post_content($boundary, $postdata, $file_name, $file_field) { + if(empty($file_name) || empty($file_field)) { + return dsq_get_query_string($postdata); + } + + $content = array(); + $content[] = '--' . $boundary; + foreach($postdata as $key=>$value) { + $content[] = 'Content-Disposition: form-data; name="' . $key . '"' . "\r\n\r\n" . $value; + $content[] = '--' . $boundary; + } + $content[] = 'Content-Disposition: form-data; name="' . $file_field . '"; filename="' . $file_name . '"'; + // HACK: We only need to handle text/plain files right now. + $content[] = "Content-Type: text/plain\r\n"; + $content[] = file_get_contents($file_name); + $content[] = '--' . $boundary . '--'; + $content = implode("\r\n", $content); + return $content; +} + + +function dsq_get_http_headers_for_request($boundary, $content, $file_name, $file_field) { + $headers = array(); + $headers[] = 'User-Agent: ' . USER_AGENT; + $headers[] = 'Connection: close'; + if($content) { + $headers[] = 'Content-Length: ' . strlen($content); + if($file_name && $file_field) { + $headers[] = 'Content-Type: multipart/form-data; boundary=' . $boundary; + } else { + $headers[] = 'Content-Type: application/x-www-form-urlencoded'; + } + } + return implode("\r\n", $headers); +} + + +function _dsq_curl_urlopen($url, $postdata, &$response, $file_name, $file_field) { + $c = curl_init($url); + $postdata_str = dsq_get_query_string($postdata); + + $c_options = array( + CURLOPT_USERAGENT => USER_AGENT, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_POST => ($postdata_str ? 1 : 0), + CURLOPT_HEADER => true, + CURLOPT_HTTPHEADER => array('Expect:'), + CURLOPT_TIMEOUT => SOCKET_TIMEOUT + ); + if($postdata) { + $c_options[CURLOPT_POSTFIELDS] = $postdata_str; + } + if($file_name && $file_field) { + $postdata[$file_field] = '@' . $file_name; + $c_options[CURLOPT_POSTFIELDS] = $postdata; + $c_options[CURLOPT_RETURNTRANSFER] = 1; + } + curl_setopt_array($c, $c_options); + + $data = curl_exec($c); + list($headers, $response['data']) = explode("\r\n\r\n", $data, 2); + + $response['headers'] = _dsq_get_response_headers($headers, $response); + $response['code'] = curl_getinfo($c, CURLINFO_HTTP_CODE); +} + +function _dsq_get_response_headers($headers, &$response) { + $headers = explode("\r\n", $headers); + list($unused, $response['code'], $unused) = explode(' ', $headers[0], 3); + $headers = array_slice($headers, 1); + + // Convert headers into associative array. + foreach($headers as $unused=>$header) { + $header = explode(':', $header); + $header[0] = trim($header[0]); + $header[1] = trim($header[1]); + $headers[strtolower($header[0])] = $header[1]; + } + + return $headers; +} + +function _dsq_fsockopen_urlopen($url, $postdata, &$response, $file_name, $file_field) { + $buf = ''; + $req = ''; + $length = 0; + $boundary = '----------' . md5(time()); + $postdata_str = dsq_get_post_content($boundary, $postdata, $file_name, $file_field); + $url_pieces = parse_url($url); + + // Set default port for supported schemes if none is provided. + if(!isset($url_pieces['port'])) { + switch($url_pieces['scheme']) { + case 'http': + $url_pieces['port'] = 80; + break; + case 'https': + $url_pieces['port'] = 443; + $url_pieces['host'] = 'ssl://' . $url_pieces['host']; + break; + } + } + + // Set default path if trailing slash is not provided. + if(!isset($url_pieces['path'])) { $url_pieces['path'] = '/'; } + + // Determine if we need to include the port in the Host header or not. + if(($url_pieces['port'] == 80 && $url_pieces['scheme'] == 'http') || + ($url_pieces['port'] == 443 && $url_pieces['scheme'] == 'https')) { + $host = $url_pieces['host']; + } else { + $host = $url_pieces['host'] . ':' . $url_pieces['port']; + } + + $fp = @fsockopen($url_pieces['host'], $url_pieces['port'], $errno, $errstr, SOCKET_TIMEOUT); + if(!$fp) { return false; } + + $path = $url_pieces['path']; + if ($url_pieces['query']) $path .= '?'.$url_pieces['query']; + + $req .= ($postdata_str ? 'POST' : 'GET') . ' ' . $path . " HTTP/1.1\r\n"; + $req .= 'Host: ' . $host . "\r\n"; + $req .= dsq_get_http_headers_for_request($boundary, $postdata_str, $file_name, $file_field); + if($postdata_str) { + $req .= "\r\n\r\n" . $postdata_str; + } + $req .= "\r\n\r\n"; + + fwrite($fp, $req); + while(!feof($fp)) { + $buf .= fgets($fp, 4096); + } + + // Parse headers from the response buffers. + list($headers, $response['data']) = explode("\r\n\r\n", $buf, 2); + + // Get status code from headers. + $headers = _dsq_get_response_headers($headers, $response); + + // If transfer-coding is set to chunked, we need to join the message body + // together. + if(isset($headers['transfer-encoding']) && 'chunked' == strtolower($headers['transfer-encoding'])) { + $chunk_data = $response['data']; + $joined_data = ''; + while(true) { + // Strip length from body. + list($chunk_length, $chunk_data) = explode("\r\n", $chunk_data, 2); + $chunk_length = hexdec($chunk_length); + if(!$chunk_length || !strlen($chunk_data)) { break; } + + $joined_data .= substr($chunk_data, 0, $chunk_length); + $chunk_data = substr($chunk_data, $chunk_length + 1); + $length += $chunk_length; + } + $response['data'] = $joined_data; + } else { + $length = $headers['content-length']; + } + $response['headers'] = $headers; +} + + +function _dsq_fopen_urlopen($url, $postdata, &$response, $file_name, $file_field) { + $params = array(); + if($file_name && $file_field) { + $boundary = '----------' . md5(time()); + $content = dsq_get_post_content($boundary, $postdata, $file_name, $file_field); + $header = dsq_get_http_headers_for_request($boundary, $content, $file_name, $file_field); + + $params = array('http' => array( + 'method' => 'POST', + 'header' => $header, + 'content' => $content, + 'timeout' => SOCKET_TIMEOUT + )); + } else { + if($postdata) { + $params = array('http' => array( + 'method' => 'POST', + 'header' => 'Content-Type: application/x-www-form-urlencoded', + 'content' => dsq_get_query_string($postdata), + 'timeout' => SOCKET_TIMEOUT + )); + } + } + + + ini_set('user_agent', USER_AGENT); + $ctx = stream_context_create($params); + $fp = fopen($url, 'rb', false, $ctx); + if(!$fp) { + return false; + } + + // Get status code from headers. + list($unused, $response['code'], $unused) = explode(' ', $http_response_header[0], 3); + $headers = array_slice($http_response_header, 1); + + // Convert headers into associative array. + foreach($headers as $unused=>$header) { + $header = explode(':', $header); + $header[0] = trim($header[0]); + $header[1] = trim($header[1]); + $headers[strtolower($header[0])] = strtolower($header[1]); + } + + $response['data'] = stream_get_contents($fp); + $response['headers'] = $headers; +} + + +/** + * Wrapper to provide a single interface for making an HTTP request. + * + * Attempts to use cURL, fopen(), or fsockopen(), whichever is available + * first. + * + * @param string $url URL to make request to. + * @param array $postdata (optional) If postdata is provided, the request + * method is POST with the key/value pairs as + * the data. + * @param array $file (optional) Should provide associative array + * with two keys: name and field. Name should + * be the name of the file and field is the name + * of the field to POST. + */ +function dsq_urlopen($url, $postdata=false, $file=false) { + $response = array( + 'data' => '', + 'code' => 0 + ); + + if($file) { + extract($file, EXTR_PREFIX_ALL, 'file'); + } + if(empty($file_name) || empty($file_field)) { + $file_name = false; + $file_field = false; + } + +// + + // Try curl, fsockopen, fopen + stream (PHP5 only), exec wget + // Don't use cURL on IIS servers because it doesn't explicitly specify a CA bundle by default + if(function_exists('curl_init') && strpos($_SERVER['SERVER_SOFTWARE'], 'IIS') == false) { + if (!function_exists('curl_setopt_array')) { + function curl_setopt_array(&$ch, $curl_options) + { + foreach ($curl_options as $option => $value) { + if (!curl_setopt($ch, $option, $value)) { + return false; + } + } + return true; + } + } + _dsq_curl_urlopen($url, $postdata, $response, $file_name, $file_field); + } else if(ini_get('allow_url_fopen') && function_exists('stream_get_contents')) { + _dsq_fopen_urlopen($url, $postdata, $response, $file_name, $file_field); + } else { + // TODO: Find the failure condition for fsockopen() (sockets?) + _dsq_fsockopen_urlopen($url, $postdata, $response, $file_name, $file_field); + } + +// returns array with keys data and code (from headers) + + return $response; +} + +function dsq_url_method() { + if(function_exists('curl_init')) { + return 'curl'; + } else if(ini_get('allow_url_fopen') && function_exists('stream_get_contents')) { + return 'fopen'; + } else { + return 'fsockopen'; + } +} +?> diff --git a/disqus/lib/wp-api.php b/disqus/lib/wp-api.php index efe7708..b1f493c 100644 --- a/disqus/lib/wp-api.php +++ b/disqus/lib/wp-api.php @@ -3,8 +3,8 @@ * Implementation of the Disqus API designed for WordPress. * * @author Disqus - * @copyright 2007-2010 Big Head Labs - * @link http://disqus.com/ + * @copyright 2007-2016 Big Head Labs + * @link https://disqus.com/ * @package Disqus * @subpackage DisqusWordPressAPI * @version 2.0 @@ -33,7 +33,7 @@ class DisqusWordPressAPI { var $short_name; var $forum_api_key; - function DisqusWordPressAPI($short_name=null, $forum_api_key=null, $user_api_key=null) { + function __construct($short_name=null, $forum_api_key=null, $user_api_key=null) { $this->short_name = $short_name; $this->forum_api_key = $forum_api_key; $this->user_api_key = $user_api_key; @@ -79,6 +79,7 @@ function import_wordpress_comments(&$wxr, $timestamp, $eof=true) { DISQUS_IMPORTER_URL . 'api/import-wordpress-comments/', array( 'method' => 'POST', + 'timeout' => 60, 'body' => array( 'forum_url' => $this->short_name, 'forum_api_key' => $this->forum_api_key, @@ -86,10 +87,10 @@ function import_wordpress_comments(&$wxr, $timestamp, $eof=true) { 'wxr' => $wxr, 'timestamp' => $timestamp, 'eof' => (int)$eof - ) + ), ) ); - if ($response->errors) { + if ($response['response']['code'] !== 200) { // hack $this->api->last_error = $response->errors; return -1; diff --git a/disqus/locales/default.mo b/disqus/locales/default.mo index dfc9def..b6551e4 100644 Binary files a/disqus/locales/default.mo and b/disqus/locales/default.mo differ diff --git a/disqus/locales/default.po b/disqus/locales/default.po index 6005284..5e1ae7d 100644 --- a/disqus/locales/default.po +++ b/disqus/locales/default.po @@ -2,428 +2,489 @@ msgid "" msgstr "" "Project-Id-Version: disqus-wordpress\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-01-04 12:02-0800\n" -"PO-Revision-Date: 2013-01-04 12:03-0800\n" -"Last-Translator: Tyler Hayes \n" -"Language-Team: DISQUS \n" +"POT-Creation-Date: 2014-11-10 11:06-0800\n" +"PO-Revision-Date: 2014-11-10 11:07-0800\n" +"Last-Translator: Ryan \n" +"Language-Team: Disqus \n" +"Language: en_US\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-KeywordsList: _;gettext;gettext_noop;dsq_i;__;_e\n" "X-Poedit-Basepath: ../\n" -"X-Generator: Poedit 1.5.4\n" +"X-Generator: Poedit 1.6.10\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Poedit-SearchPath-0: ..\n" -#: ../disqus/comments.php:18 ../disqus/comments.php:34 -msgid " Older Comments" +#: ../disqus/comments.php:15 ../disqus/comments.php:37 +msgid "Older Comments" msgstr "" -#: ../disqus/comments.php:19 ../disqus/comments.php:35 -msgid "Newer Comments " +#: ../disqus/comments.php:18 ../disqus/comments.php:40 +msgid "Newer Comments" msgstr "" -#: ../disqus/disqus.php:446 +#: ../disqus/disqus.php:178 +msgid "Disqus needs to be configured" +msgstr "" + +#: ../disqus/disqus.php:179 +msgid "Configure Disqus by clicking Comments to the left." +msgstr "" + +#: ../disqus/disqus.php:527 msgid "" -"Your comments have been sent to Disqus and queued for import!
    try again

    If your API key has changed, you " -"may need to reinstall Disqus (deactivate the plugin and then reactivate it). " -"If you are still having issues, refer to the WordPress help page." +"If your API key has changed, you may need to reinstall Disqus (deactivate " +"the plugin and then reactivate it)." msgstr "" -#: ../disqus/disqus.php:465 +#: ../disqus/disqus.php:577 #, php-format +msgid "If you are still having issues, refer to the %s WordPress help page" +msgstr "" + +#: ../disqus/disqus.php:608 msgid "" -"Your comments have been sent to Disqus and queued for import!
    See the status of your import at Disqus" +"Unable to import comments. Make sure you are accessing this page from the " +"Wordpress dashboard." msgstr "" -#: ../disqus/disqus.php:495 +#: ../disqus/disqus.php:631 msgid "There was an error downloading your comments from Disqus." msgstr "" -#: ../disqus/disqus.php:500 +#: ../disqus/disqus.php:636 msgid "" "Your comments have been downloaded from Disqus and saved in your local " "database." msgstr "" -#: ../disqus/disqus.php:503 +#: ../disqus/disqus.php:639 #, php-format -msgid "Import in progress (last post id: %s) …" +msgid "Import in progress (last post id: %s)" msgstr "" -#: ../disqus/disqus.php:837 +#: ../disqus/disqus.php:989 msgid "Pingback:" msgstr "" -#: ../disqus/disqus.php:837 -msgid "(Edit)" +#: ../disqus/disqus.php:989 +msgid "Edit" msgstr "" -#: ../disqus/disqus.php:874 +#: ../disqus/disqus.php:1026 msgid "Configure" msgstr "" -#: ../disqus/disqus.php:876 ../disqus/manage.php:258 +#: ../disqus/disqus.php:1028 ../disqus/manage.php:394 msgid "Settings" msgstr "" -#: ../disqus/disqus.php:1578 +#: ../disqus/disqus.php:1492 msgid "" "Sorry, the built-in commenting system is disabled because Disqus is active." msgstr "" -#: ../disqus/manage.php:38 +#: ../disqus/manage.php:62 msgid "Disqus Reset" msgstr "" -#: ../disqus/manage.php:40 +#: ../disqus/manage.php:65 msgid "Disqus has been reset successfully." msgstr "" -#: ../disqus/manage.php:42 +#: ../disqus/manage.php:67 msgid "Local settings for the plugin were removed." msgstr "" -#: ../disqus/manage.php:43 +#: ../disqus/manage.php:68 msgid "Database changes by Disqus were reverted." msgstr "" -#: ../disqus/manage.php:45 -msgid "" -"If you wish to reinstall, you can do " -"that now." +#: ../disqus/manage.php:71 +msgid "If you wish to reinstall, you can do that now." +msgstr "" + +#: ../disqus/manage.php:72 +msgid "Reinstall" msgstr "" -#: ../disqus/manage.php:83 +#: ../disqus/manage.php:189 msgid "Your settings have been changed." msgstr "" -#: ../disqus/manage.php:106 -msgid "" -"There was an error completing the installation of Disqus. If you are still " -"having issues, refer to the WordPress help page." +#: ../disqus/manage.php:220 +msgid "There was an error completing the installation of Disqus." msgstr "" -#: ../disqus/manage.php:135 -#, php-format +#: ../disqus/manage.php:222 +msgid "If you are still having issues, refer to the help documentation." +msgstr "" + +#: ../disqus/manage.php:225 +msgid "WordPress Help Page" +msgstr "" + +#: ../disqus/manage.php:258 msgid "" -"There aren't any sites associated with this account. Maybe you want to create a site?" +"There aren't any sites associated with this account. Maybe you want to " +"create a site?" +msgstr "" + +#: ../disqus/manage.php:261 +msgid "Create a site" msgstr "" -#: ../disqus/manage.php:145 +#: ../disqus/manage.php:274 msgid "Moderate" msgstr "" -#: ../disqus/manage.php:145 +#: ../disqus/manage.php:274 msgid "Install" msgstr "" -#: ../disqus/manage.php:146 +#: ../disqus/manage.php:277 msgid "Plugin Settings" msgstr "" -#: ../disqus/manage.php:155 ../disqus/manage.php:166 ../disqus/manage.php:200 +#: ../disqus/manage.php:287 ../disqus/manage.php:301 ../disqus/manage.php:335 msgid "Install Disqus Comments" msgstr "" -#: ../disqus/manage.php:157 +#: ../disqus/manage.php:289 msgid "Disqus has been installed on your blog." msgstr "" -#: ../disqus/manage.php:158 +#: ../disqus/manage.php:291 +msgid "If you have existing comments, you may wish to export them now." +msgstr "" + +#: ../disqus/manage.php:292 msgid "" -"If you have existing comments, you may wish to export them now. Otherwise, you're all set, and the " -"Disqus network is now powering comments on your blog." +"Otherwise, you're all set, and the Disqus network is now powering comments " +"on your site." msgstr "" -#: ../disqus/manage.php:159 +#: ../disqus/manage.php:294 msgid "Continue to the moderation dashboard" msgstr "" -#: ../disqus/manage.php:172 +#: ../disqus/manage.php:307 msgid "Select a website" msgstr "" -#: ../disqus/manage.php:184 +#: ../disqus/manage.php:319 msgid "Or register a new one on the Disqus website." msgstr "" -#: ../disqus/manage.php:206 -msgid "Username" +#: ../disqus/manage.php:341 +msgid "Username or email" msgstr "" -#: ../disqus/manage.php:209 -msgid "(don't have a Disqus Profile yet?)" +#: ../disqus/manage.php:344 +msgid "don't have a Disqus Profile yet?" msgstr "" -#: ../disqus/manage.php:213 +#: ../disqus/manage.php:348 msgid "Password" msgstr "" -#: ../disqus/manage.php:216 -msgid "(forgot your password?)" +#: ../disqus/manage.php:351 +msgid "forgot your password?" +msgstr "" + +#: ../disqus/manage.php:371 +msgid "Go to Disqus Moderation" msgstr "" -#: ../disqus/manage.php:259 +#: ../disqus/manage.php:395 #, php-format msgid "Version: %s" msgstr "" -#: ../disqus/manage.php:263 -msgid "" -"

    Disqus comments are currently disabled. (Enable)

    " +#: ../disqus/manage.php:401 +msgid "Disqus comments are currently " msgstr "" -#: ../disqus/manage.php:265 -msgid "" -"

    Disqus comments are currently enabled. (Disable)

    " +#: ../disqus/manage.php:404 +msgid "Disable" msgstr "" -#: ../disqus/manage.php:273 -msgid "

    General

    " +#: ../disqus/manage.php:404 +msgid "Enable" msgstr "" -#: ../disqus/manage.php:276 +#: ../disqus/manage.php:413 +msgid "General" +msgstr "" + +#: ../disqus/manage.php:416 msgid "Forum Shortname" msgstr "" -#: ../disqus/manage.php:281 +#: ../disqus/manage.php:421 msgid "" "This is the unique identifier for your website in Disqus, automatically set " "during installation." msgstr "" -#: ../disqus/manage.php:286 -msgid "

    Appearance

    " +#: ../disqus/manage.php:426 +msgid "Appearance" msgstr "" -#: ../disqus/manage.php:289 +#: ../disqus/manage.php:429 msgid "Use Disqus Comments on" msgstr "" -#: ../disqus/manage.php:292 -msgid "On all existing and future blog posts." +#: ../disqus/manage.php:432 +msgid "All blog posts." msgstr "" -#: ../disqus/manage.php:293 -msgid "Only on blog posts with closed comments." +#: ../disqus/manage.php:433 +msgid "Blog posts with closed comments only." msgstr "" -#: ../disqus/manage.php:296 -msgid "Your WordPress comments will never be lost." +#: ../disqus/manage.php:437 +msgid "" +"You have selected to only enable Disqus on posts with closed comments. If " +"you aren't seeing Disqus on new posts, change this option to \"All blog posts" +"\"." msgstr "" -#: ../disqus/manage.php:301 -msgid "

    Sync

    " +#: ../disqus/manage.php:438 +msgid "" +"Shows comments on either all blog posts, or ones with closed comments. " +"Select the \"Blog posts with closed comments only\" option if you plan on " +"disabling Disqus, but want to keep it on posts which already have comments." msgstr "" -#: ../disqus/manage.php:304 -msgid "Comment Sync" +#: ../disqus/manage.php:444 +msgid "Sync" msgstr "" -#: ../disqus/manage.php:307 +#: ../disqus/manage.php:447 +msgid "Comment Importing" +msgstr "" + +#: ../disqus/manage.php:450 msgid "Disable automated comment importing" msgstr "" -#: ../disqus/manage.php:308 +#: ../disqus/manage.php:451 msgid "" "If you have problems with WP-Cron taking too long, or have a large number of " -"comments, you may wish to disable automated sync. Keep in mind this means " -"comments will not automatically sync to your local WordPress database." +"comments, you may wish to disable automated sync. Comments will only be " +"imported to your local Wordpress database if you do so manually." msgstr "" -#: ../disqus/manage.php:312 +#: ../disqus/manage.php:455 msgid "Server-Side Rendering" msgstr "" -#: ../disqus/manage.php:315 +#: ../disqus/manage.php:458 msgid "Disable server-side rendering of comments" msgstr "" -#: ../disqus/manage.php:316 +#: ../disqus/manage.php:459 msgid "Hides comments from nearly all search engines." msgstr "" -#: ../disqus/manage.php:321 -msgid "

    Patches

    " +#: ../disqus/manage.php:464 +msgid "Patches" +msgstr "" + +#: ../disqus/manage.php:468 +msgid "External Javascript Files" +msgstr "" + +#: ../disqus/manage.php:471 +msgid "Render Javascript in external files" msgstr "" -#: ../disqus/manage.php:325 +#: ../disqus/manage.php:472 +msgid "" +"This will render the Disqus scripts as external files in the footer as " +"recommended by Wordpress. Disable this if are not seeing Disqus appear on " +"pages that normally have comments. This will fix the issue if your theme " +"does not support the 'wp_enqueue_script' function, are caching your site on " +"a CDN." +msgstr "" + +#: ../disqus/manage.php:477 msgid "Template Conflicts" msgstr "" -#: ../disqus/manage.php:328 +#: ../disqus/manage.php:480 msgid "Output JavaScript in footer" msgstr "" -#: ../disqus/manage.php:329 -#, php-format +#: ../disqus/manage.php:481 msgid "" "Enable this if you have problems with comment counts or other " "irregularities. For example: missing counts, counts always at 0, Disqus code " "showing on the page, broken image carousels, or longer-than-usual home page " -"load times (more info)." +"load times" msgstr "" -#: ../disqus/manage.php:334 -#, php-format -msgid "" -"

    Advanced

    Single Sign-On

    Allows users to log in to Disqus " -"via WordPress. (More info on SSO)

    " +#: ../disqus/manage.php:487 +msgid "Advanced" +msgstr "" + +#: ../disqus/manage.php:488 +msgid "Single Sign-On" +msgstr "" + +#: ../disqus/manage.php:490 +msgid "Allows users to log in to Disqus via WordPress." +msgstr "" + +#: ../disqus/manage.php:492 +msgid "More info on SSO" msgstr "" -#: ../disqus/manage.php:338 +#: ../disqus/manage.php:499 msgid "Disqus Partner Key" msgstr "" -#: ../disqus/manage.php:345 +#: ../disqus/manage.php:506 msgid "API Application Public Key" msgstr "" -#: ../disqus/manage.php:349 ../disqus/manage.php:357 -#, php-format -msgid "Found at Disqus API Applications." +#: ../disqus/manage.php:510 ../disqus/manage.php:518 +msgid "Disqus API Applications" msgstr "" -#: ../disqus/manage.php:353 +#: ../disqus/manage.php:514 msgid "API Application Secret Key" msgstr "" -#: ../disqus/manage.php:361 +#: ../disqus/manage.php:522 msgid "Custom Log-in Button" msgstr "" -#: ../disqus/manage.php:411 ../disqus/manage.php:471 +#: ../disqus/manage.php:536 msgid "Change" msgstr "" -#: ../disqus/manage.php:411 ../disqus/manage.php:471 +#: ../disqus/manage.php:536 msgid "Choose" msgstr "" -#: ../disqus/manage.php:411 +#: ../disqus/manage.php:536 msgid "button" msgstr "" -#: ../disqus/manage.php:417 -#, php-format -msgid "" -"Adds a button to the Disqus log-in interface. (Example " -"screenshot.)" +#: ../disqus/manage.php:542 +msgid "Adds a button to the Disqus log-in interface." msgstr "" -#: ../disqus/manage.php:418 -#, php-format -msgid "" -"
    See our SSO button documentation for a template to " -"create your own button." +#: ../disqus/manage.php:543 +msgid "Example screenshot" msgstr "" -#: ../disqus/manage.php:422 -msgid "Custom Log-in Icon
    " +#: ../disqus/manage.php:545 +msgid "See our documentation for a template to create your own button." msgstr "" -#: ../disqus/manage.php:471 -msgid "icon" +#: ../disqus/manage.php:546 +msgid "SSO button documentation" msgstr "" -#: ../disqus/manage.php:477 -#, php-format -msgid "" -"Adds an icon to the Disqus Classic log-in modal. This does not apply for " -"sites using Disqus 2012. (Example screenshot.)" -msgstr "" - -#: ../disqus/manage.php:478 -msgid "
    Dimensions: 16x16." -msgstr "" - -#: ../disqus/manage.php:496 +#: ../disqus/manage.php:564 msgid "Export comments to Disqus" msgstr "" -#: ../disqus/manage.php:499 +#: ../disqus/manage.php:570 msgid "Export Comments" msgstr "" -#: ../disqus/manage.php:499 +#: ../disqus/manage.php:571 msgid "This will export your existing WordPress comments to Disqus" msgstr "" -#: ../disqus/manage.php:505 +#: ../disqus/manage.php:579 msgid "Sync Disqus with WordPress" msgstr "" -#: ../disqus/manage.php:509 +#: ../disqus/manage.php:586 msgid "Sync Comments" msgstr "" -#: ../disqus/manage.php:509 +#: ../disqus/manage.php:587 msgid "" "This will download your Disqus comments and store them locally in WordPress" msgstr "" -#: ../disqus/manage.php:510 +#: ../disqus/manage.php:591 msgid "Remove all imported Disqus comments before syncing." msgstr "" -#: ../disqus/manage.php:521 +#: ../disqus/manage.php:605 msgid "Reset Disqus" msgstr "" -#: ../disqus/manage.php:525 +#: ../disqus/manage.php:610 msgid "Are you sure you want to reset the Disqus plugin?" msgstr "" -#: ../disqus/manage.php:525 +#: ../disqus/manage.php:611 msgid "" "This removes all Disqus-specific settings. Comments will remain unaffected." msgstr "" -#: ../disqus/manage.php:526 +#: ../disqus/manage.php:613 msgid "" "If you have problems with resetting taking too long you may wish to first " -"manually drop the disqus_dupecheck index from your " -"commentmeta table." +"manually drop the 'disqus_dupecheck' index from your 'commentmeta' table." msgstr "" -#: ../disqus/manage.php:533 +#: ../disqus/manage.php:620 msgid "Debug Information" msgstr "" -#: ../disqus/manage.php:534 -#, php-format +#: ../disqus/manage.php:622 msgid "" -"Having problems with the plugin? Check out our WordPress Troubleshooting " -"documentation. You can also drop us a line including the " -"following details and we'll do what we can." +"Having problems with the plugin? Check out our troubleshooting documentation." +msgstr "" + +#: ../disqus/manage.php:623 +msgid "WordPress troubleshooting ocumentation" +msgstr "" + +#: ../disqus/manage.php:624 +msgid "You can also email us and include the debug info below." +msgstr "" + +#: ../disqus/manage.php:625 +msgid "Contact support" msgstr "" #: ../disqus/upgrade.php:12 msgid "Upgrade Disqus Comments" msgstr "" -#: ../disqus/upgrade.php:14 +#: ../disqus/upgrade.php:15 msgid "You need to upgrade your database to continue." msgstr "" diff --git a/disqus/locales/index.html b/disqus/locales/index.html deleted file mode 100644 index e69de29..0000000 diff --git a/disqus/manage.php b/disqus/manage.php index 520089a..bd48dc8 100644 --- a/disqus/manage.php +++ b/disqus/manage.php @@ -1,23 +1,46 @@ $value ) { + if ( isset($_POST[$nonce_form_prefix.$value]) ) { + check_admin_referer($nonce_action_prefix.$value, $nonce_form_prefix.$value); + return true; + } + } + + return false; } -if(isset($_POST['dsq_password'])) { - $_POST['dsq_password'] = stripslashes($_POST['dsq_password']); +if ( ! empty($_POST) ) { + $nonce_result_check = has_valid_nonce(); + if ($nonce_result_check === false) { + die('Unable to save changes. Make sure you are accessing this page from the Wordpress dashboard.'); + } } -// HACK: For old versions of WordPress -if ( !function_exists('wp_nonce_field') ) { - function wp_nonce_field() {} +if( isset($_POST['dsq_username']) ) { + $_POST['dsq_username'] = stripslashes($_POST['dsq_username']); +} + +if( isset($_POST['dsq_password']) ) { + $_POST['dsq_password'] = stripslashes($_POST['dsq_password']); } // Handle export function. @@ -34,57 +57,140 @@ function wp_nonce_field() {} unset($_POST); dsq_reset_database(); ?> +

    +

    -

    reinstall, you can do that now.') ?>

    +

    + +   +

    array( + 'key_name' => 'dsq_user_api_key', + 'min' => 64, + 'max' => 64, + ), + 'disqus_api_key' => array( + 'key_name' => 'disqus_api_key', + 'min' => 64, + 'max' => 64, + ), + 'disqus_public_key' => array( + 'key_name' => 'disqus_public_key', + 'min' => 64, + 'max' => 64, + ), + 'disqus_secret_key' => array( + 'key_name' => 'disqus_secret_key', + 'min' => 64, + 'max' => 64, + ), + 'disqus_partner_key' => array( + 'key_name' => 'disqus_partner_key', + 'min' => 64, + 'max' => 64, + ), + 'dsq_forum' => array( + 'key_name' => 'dsq_forum', + 'min' => 1, + 'max' => 64, + ), + 'disqus_forum_url' => array( + 'key_name' => 'disqus_forum_url', + 'min' => 1, + 'max' => 64, + ), + 'disqus_replace' => array( + 'key_name' => 'disqus_replace', + 'min' => 3, + 'max' => 6, + ), + 'dsq_username' => array( + 'key_name' => 'dsq_username', + 'min' => 3, + 'max' => 250, + ), + ); + +// Check keys keys and remove bad input. +foreach ( $check_fields as $key ) { + + if ( isset($_POST[$key['key_name']]) ) { + + // Strip tags before checking + $_POST[$key['key_name']] = trim(strip_tags($_POST[$key['key_name']])); + + // Check usernames independently because they can have special characters + // or be email addresses + if ( 'dsq_username' === $key['key_name'] ) { + if ( !is_valid_dsq_username($_POST[$key['key_name']], $key['min'], $key['max']) ) { + unset($_POST[$key['key_name']]); + } + } + else { + if ( !is_valid_dsq_key($_POST[$key['key_name']], $key['min'], $key['max']) ) { + unset($_POST[$key['key_name']]); + } + } + } } +function is_valid_dsq_username($value, $min=3, $max=250) { + if ( is_email($value) ) { + return true; + } + else { + return is_valid_dsq_key($value, $min, $max); + } +} + +function is_valid_dsq_key($value, $min=1, $max=64) { + return preg_match('/^[\0-9\\:A-Za-z_-]{'.$min.','.$max.'}+$/', $value); +} // Handle advanced options. if ( isset($_POST['disqus_forum_url']) && isset($_POST['disqus_replace']) ) { - update_option('disqus_partner_key', trim(stripslashes($_POST['disqus_partner_key']))); - update_option('disqus_replace', $_POST['disqus_replace']); + update_option('disqus_partner_key', isset($_POST['disqus_partner_key']) ? esc_attr( trim(stripslashes($_POST['disqus_partner_key'])) ) : ''); + update_option('disqus_replace', isset($_POST['disqus_replace']) ? esc_attr( $_POST['disqus_replace'] ) : 'all'); update_option('disqus_cc_fix', isset($_POST['disqus_cc_fix'])); + update_option('dsq_external_js', isset($_POST['dsq_external_js']) ? '1' : '0'); update_option('disqus_manual_sync', isset($_POST['disqus_manual_sync'])); update_option('disqus_disable_ssr', isset($_POST['disqus_disable_ssr'])); - update_option('disqus_public_key', $_POST['disqus_public_key']); - update_option('disqus_secret_key', $_POST['disqus_secret_key']); - // Handle any SSO button and icon uploads + update_option('disqus_public_key', isset($_POST['disqus_public_key']) ? esc_attr( $_POST['disqus_public_key'] ) : ''); + update_option('disqus_secret_key', isset($_POST['disqus_secret_key']) ? esc_attr( $_POST['disqus_secret_key'] ) : ''); + // Handle SSO button uploads if ( version_compare($wp_version, '3.5', '>=') ) { // Use WP 3.5's new, streamlined, much-improved built-in media uploader - // Only update if a value is actually POSTed, otherwise any time the form is saved the button and icon will be un-set - if ($_POST['disqus_sso_button']) { update_option('disqus_sso_button', $_POST['disqus_sso_button']); } - if ($_POST['disqus_sso_icon']) { update_option('disqus_sso_icon', $_POST['disqus_sso_icon']); } + // Only update if a value is actually POSTed, otherwise any time the form is saved the button will be un-set + if ( $_POST['disqus_sso_button'] ) { + update_option('disqus_sso_button', isset($_POST['disqus_sso_button']) ? esc_url( $_POST['disqus_sso_button'] ) : ''); + } } else { // WP is older than 3.5, use legacy, less-elegant media uploader if(isset($_FILES['disqus_sso_button'])) { dsq_image_upload_handler('disqus_sso_button'); } - if(isset($_FILES['disqus_sso_icon'])) { - dsq_image_upload_handler('disqus_sso_icon'); - } } dsq_manage_dialog(dsq_i('Your settings have been changed.')); } // handle disqus_active -if (isset($_GET['active'])) { +if ( isset($_POST['active']) && isset($_GET['active']) ) { update_option('disqus_active', ($_GET['active'] == '1' ? '1' : '0')); } @@ -99,15 +205,31 @@ function wp_nonce_field() {} // Handle installation process. if ( 3 == $step && isset($_POST['dsq_forum']) && isset($_POST['dsq_user_api_key']) ) { list($dsq_forum_id, $dsq_forum_url) = explode(':', $_POST['dsq_forum']); - update_option('disqus_forum_url', $dsq_forum_url); + update_option('disqus_forum_url', esc_attr( $dsq_forum_url ) ); + + // Output javascript in external files by default + update_option('dsq_external_js', '1'); + + // Output Javascript in footer by default (no effect when dsq_external_js is enabld) + update_option('disqus_cc_fix', '1'); + $api_key = $dsq_api->get_forum_api_key($_POST['dsq_user_api_key'], $dsq_forum_id); if ( !$api_key || $api_key < 0 ) { update_option('disqus_replace', 'replace'); - dsq_manage_dialog(dsq_i('There was an error completing the installation of Disqus. If you are still having issues, refer to the WordPress help page.'), true); + dsq_manage_dialog( + dsq_i('There was an error completing the installation of Disqus.') + . ' ' + . dsq_i('If you are still having issues, refer to the help documentation.') + . ' ' + . '' + . dsq_i('WordPress Help Page') + . '', + true); } else { - update_option('disqus_api_key', $api_key); - update_option('disqus_user_api_key', $_POST['dsq_user_api_key']); + update_option('disqus_api_key', esc_attr( $api_key )); + update_option('disqus_user_api_key', esc_attr( $_POST['dsq_user_api_key']) ); update_option('disqus_replace', 'all'); + update_option('disqus_active', '1'); } if (!empty($_POST['disqus_partner_key'])) { @@ -132,7 +254,13 @@ function wp_nonce_field() {} dsq_manage_dialog($dsq_api->get_last_error(), true); } else if ( !$dsq_sites ) { $step = 1; - dsq_manage_dialog(dsq_i('There aren\'t any sites associated with this account. Maybe you want to create a site?', 'http://disqus.com/admin/register/'), true); + dsq_manage_dialog( + dsq_i('There aren\'t any sites associated with this account. Maybe you want to create a site?') + . ' ' + . '' + . dsq_i('Create a site') + . '', + true); } } } @@ -142,8 +270,12 @@ function wp_nonce_field() {} ?>
      - id="dsq-tab-main" rel="dsq-main"> - id="dsq-tab-advanced" rel="dsq-advanced"> + id="dsq-tab-main" rel="dsq-main"> + + + id="dsq-tab-advanced" rel="dsq-advanced"> + +
    @@ -155,7 +287,10 @@ function wp_nonce_field() {}

    -

    export them now. Otherwise, you\'re all set, and the Disqus network is now powering comments on your blog.'); ?>

    +

    +   + +

    - + @@ -174,21 +309,21 @@ function wp_nonce_field() {} $dsq_site ): ?> - - + +

    - +

    - - + +

    @@ -200,41 +335,40 @@ function wp_nonce_field() {}

    - - - - - - - - - - -
    - - -
    - - -
    - -

    - -

    - - + + + + + + + + + + +
    + + () +
    + + () +
    + +

    + +

    @@ -246,31 +380,37 @@ function wp_nonce_field() {} $dsq_user_api_key = get_option('disqus_user_api_key'); $dsq_partner_key = get_option('disqus_partner_key'); $dsq_cc_fix = get_option('disqus_cc_fix'); + $dsq_external_js = get_option('dsq_external_js'); $dsq_manual_sync = get_option('disqus_manual_sync'); $dsq_disable_ssr = get_option('disqus_disable_ssr'); $dsq_public_key = get_option('disqus_public_key'); $dsq_secret_key = get_option('disqus_secret_key'); $dsq_sso_button = get_option('disqus_sso_button'); - $dsq_sso_icon = get_option('disqus_sso_icon'); + $disqus_enabled = get_option('disqus_active') == '1'; + $disqus_enabled_state = $disqus_enabled ? 'enabled' : 'disabled'; ?>