WordPress.org

Make WordPress Core

Ticket #9798: spellcheck.patch

File spellcheck.patch, 14.1 KB (added by bforchhammer, 9 years ago)

Updated patch against current HEAD

  • wp-admin/admin-ajax.php

     
    111111
    112112        die('0');
    113113        break;
     114case 'spellcheck':
     115        require_once(ABSPATH . 'wp-admin/includes/spellchecker.php');
     116        wp_spellcheck_ajax();
     117        die('0');
     118break;
    114119default :
    115120        do_action( 'wp_ajax_' . $_GET['action'] );
    116121        die('0');
  • wp-admin/includes/class-wp-googlespell.php

     
     1<?php
     2/**
     3 * File contains a wordpress adapted version of TinyMCE's GoogleSpell class.
     4 *
     5 * @package WordPress
     6 * @author Benedikt Forchhammer <b.forchhammer@mind2.de>
     7 * @since       2.9.0
     8 */
     9
     10// The SpellChecking Engine that we want to extend
     11require_once( MCE_SPELLCHECKER_DIR . "/classes/GoogleSpell.php" );
     12
     13/**
     14 * Extension of TinyMCE GoogleSpell class for Wordpress
     15 *
     16 * WP_GoogleSpell extends TinyMCE's GoogleSpell class. It overrides the way in which the
     17 * http request to google is executed and uses wp_remote_post() instead of curl/fsockopen.
     18 *
     19 * @link http://trac.wordpress.org/ticket/9798 Request for proxy support for spellchecking
     20 * @since       2.9.0
     21 */
     22class WP_GoogleSpell extends GoogleSpell {
     23
     24        function &_getMatches($lang, $str) {
     25                if (function_exists('wp_remote_post')) {
     26                        // request url
     27                        $url = "https://www.google.com/tbproxy/spell?lang=" . $lang . "&hl=en";
     28                       
     29                        // Setup XML request
     30                        $xml = '<?xml version="1.0" encoding="utf-8" ?><spellrequest textalreadyclipped="0" ignoredups="0" ignoredigits="1" ignoreallcaps="1"><text>' . $str . '</text></spellrequest>';
     31                       
     32                        // set up request arguments.
     33                        $args = array( 'body' => $xml, 'sslverify' => false );
     34
     35                        // execute request and get response
     36                        $response = wp_remote_post($url, $args);
     37                       
     38                        if (is_wp_error($response)) {
     39                                wp_spellcheck_rpc_error(implode("\n", $response->get_error_messages()));
     40                        }
     41                        else {
     42                                // Grab and parse content
     43                                $matches = array();
     44                                preg_match_all('/<c o="([^"]*)" l="([^"]*)" s="([^"]*)">([^<]*)<\/c>/', wp_remote_retrieve_body($response), $matches, PREG_SET_ORDER);
     45                       
     46                                return $matches;
     47                        }
     48                }
     49                else {
     50                        wp_spellcheck_rpc_error('wp_remote_post() function has not been loaded.');
     51                }
     52        }
     53       
     54        /**
     55         * Use wordpress function unhtmlentities()
     56         *
     57         * @see http://core.trac.wordpress.org/ticket/8689
     58         * @see http://core.trac.wordpress.org/ticket/9805
     59         */
     60        function _unhtmlentities($string) {
     61                if (function_exists('unhtmlentities')) return unhtmlentities($string);
     62                else return parent::_unhtmlentities($string);
     63        }
     64}
     65?>
     66 No newline at end of file
  • wp-admin/includes/post.php

     
    12991299                'theme_advanced_buttons4' => "$mce_buttons_4",
    13001300                'language' => "$mce_locale",
    13011301                'spellchecker_languages' => "$mce_spellchecker_languages",
     1302                'spellchecker_rpc_url' => admin_url( 'admin-ajax.php?action=spellcheck' ),
    13021303                'theme_advanced_toolbar_location' => 'top',
    13031304                'theme_advanced_toolbar_align' => 'left',
    13041305                'theme_advanced_statusbar_location' => 'bottom',
  • wp-admin/includes/spellchecker.php

     
     1<?php
     2/**
     3 * This File contains functions used to handle Ajax spellchecking requests.
     4 *
     5 * @package WordPress
     6 * @author      Benedikt Forchhammer <b.forchhammer@mind2.de>
     7 * @since       2.9.0
     8 */
     9
     10/**
     11 * Allows for the tinymce SpellChecker plugin directory to be moved from the default location.
     12 *
     13 * @since       2.9.0
     14 */
     15if ( !defined('MCE_SPELLCHECKER_DIR') )
     16        define( 'MCE_SPELLCHECKER_DIR', ABSPATH . WPINC . '/js/tinymce/plugins/spellchecker');
     17
     18add_filter('wp_spellcheck_engine_config','wp_spellcheck_engine_replacements');
     19
     20/**
     21 * Changes config to use WP_GoogleSpell instead of GoogleSpell.
     22 *
     23 * @param       array   $config         Config array for SpellChecker
     24 * @since       2.9.0
     25 * @return      array
     26 */
     27function wp_spellcheck_engine_replacements($config) {
     28        // replace GoogleSpell with WP_GoogleSpell
     29        if ($config['general.engine'] == 'GoogleSpell') {
     30                $config['general.engine'] = 'WP_GoogleSpell';
     31                $config['general.engine.path'] =  ABSPATH . 'wp-admin/includes/class-wp-googlespell.php';
     32        }
     33        return $config;
     34}
     35
     36/**
     37 * Handle ajax request for "spellcheck" action.
     38 *
     39 * This function is called admin-ajax.php for the GET action "spellcheck".
     40 *
     41 * @uses        apply_filters   wp_spellcheck_rpc_request
     42 * @uses        do_action               wp_spellcheck_rpc_result
     43 * @since       2.9.0
     44 * @return      void
     45 */
     46function wp_spellcheck_ajax() {
     47
     48        // set headers at this point so that they are set fatal error responses as well.
     49        wp_spellcheck_rpc_response_headers();
     50
     51        // get request data
     52        $request = wp_spellcheck_rpc_get_request();
     53        if (is_wp_error($request)) {
     54                wp_spellcheck_rpc_error($request->get_error_message());
     55        }
     56        $request = apply_filters('wp_spellcheck_rpc_request', $request);
     57       
     58        // execute and return spellcheck
     59        $result = wp_spellcheck_do_spellcheck($request['method'], $request['params']);
     60        if (is_wp_error($result)) {
     61                wp_spellcheck_rpc_error($result->get_error_message());
     62        }
     63        do_action_ref_array('wp_spellcheck_rpc_result', array( $request, &$result ));
     64       
     65        wp_spellcheck_rpc_send_response($request['id'], $result);
     66}
     67
     68/**
     69 * Calls a method on the SpellChecking Engine and returns the result.
     70 *
     71 * This function calls the method specified in $request['method']
     72 * with the parameters specified in $request['params'] on the configured
     73 * SpellChecker Engine.
     74 *
     75 * The two methods which are available by default are:
     76 *
     77 * <ul>
     78 * <li><strong>checkWords<strong>: checks an array of words for misspellings and returns array of misspelled words</li>
     79 * <li><strong>getSuggestions</strong>: retrieves a list of suggestions for a given misspelled word</li>
     80 * </ul>
     81 *
     82 * @param       string  $method         name of method
     83 * @param       array   $params         parameters
     84 * @since       2.9.0
     85 * @return      mixed   The spellchecking result or WP_Error object
     86 */
     87function wp_spellcheck_do_spellcheck ($method, $params = array()) {
     88        $spellchecker =& wp_spellcheck_get_engine();
     89       
     90        if (is_wp_error($spellchecker)) {
     91                return $spellchecker;
     92        }
     93       
     94        if (!is_object($spellchecker)) {
     95                return new WP_Error('wp-spellcheck-engine-null', __('Failed to get SpellChecker engine instance.'));
     96        }
     97               
     98        if (!method_exists($spellchecker, $method)) {
     99                // Either invalid method name or incomplete spellchecker class
     100                return new WP_Error('wp-spellcheck-engine-method-notfound', __('Failed to call method on spellchecking engine. '));
     101        }
     102       
     103        if (!is_array($params)) {
     104                $params = array($params);
     105        }
     106       
     107        $result = call_user_func_array(array($spellchecker, $method), $params);
     108       
     109        return $result;
     110}
     111
     112/**
     113 * Get spellcheck request data.
     114 *
     115 * @since       2.9.0
     116 * @return      mixed   
     117 */
     118function wp_spellcheck_rpc_get_request() {
     119
     120        // try to get raw data
     121        $raw = wp_spellcheck_rpc_raw_input();
     122        if (empty($raw)) {
     123                return new WP_Error("wp-spellcheck-request-empty", __("Could not get raw post data."));
     124        }
     125       
     126        // try to parse data as json
     127        $request = wp_spellcheck_json_decode($raw);
     128       
     129        // check we have good request data
     130        if (!is_array($request)) {
     131                return new WP_Error("wp-spellcheck-request-malformed", __("Failed parsing request as JSON: ") . print_r($request, 1) );
     132        }
     133        if (empty($request['method'])) {
     134                return new WP_Error("wp-spellcheck-request-malformed", __("Malformed JSON: missing \"method\" parameter."));
     135        }
     136        if (empty($request['params'])) {
     137                $request['params'] = array();
     138        }
     139       
     140        return $request;
     141}
     142
     143/**
     144 * Retrieves the raw request data for spellchecking request.
     145 *
     146 * The function tries the following sources and returns the
     147 * first non-empty one found:
     148 *
     149 * <ul>
     150 * <li>$_POST[json_data]</li>
     151 * <li>$_GLOBALS[HTTP_RAW_POST_DATA]</li>
     152 * <li>$HTTP_RAW_POST_DATA</li>
     153 * <li>file_get_contents("php://input")</li>
     154 * <li>fopen("php://input", "r");</li>
     155 * </ul>
     156 *
     157 * @link        http://core.trac.wordpress.org/browser/trunk/wp-includes/js/tinymce/plugins/spellchecker/rpc.php Roughly based on respective code in this file.
     158 * @since       2.9.0
     159 * @return      string Raw request data (json encoded)
     160 */
     161function wp_spellcheck_rpc_raw_input() {
     162        $raw = "";
     163
     164        // Try param
     165        if (isset($_POST["json_data"])) {
     166                $raw = $_POST["json_data"];
     167        }
     168
     169        // Try globals array
     170        if (!$raw && isset($_GLOBALS) && isset($_GLOBALS["HTTP_RAW_POST_DATA"])) {
     171                $raw = $_GLOBALS["HTTP_RAW_POST_DATA"];
     172        }
     173
     174        // Try globals variable
     175        if (!$raw && isset($HTTP_RAW_POST_DATA)) {
     176                $raw = $HTTP_RAW_POST_DATA;
     177        }
     178               
     179        // Try stream
     180        if (!$raw) {
     181                if (!function_exists('file_get_contents')) {
     182                        $fp = fopen("php://input", "r");
     183                        if ($fp) {
     184                                $raw = "";
     185
     186                                while (!feof($fp)) $raw = fread($fp, 1024);
     187                                fclose($fp);
     188                        }
     189                }
     190                else {
     191                        $raw = "" . file_get_contents("php://input");
     192                }
     193        }
     194
     195        return $raw;
     196}
     197
     198/**
     199 * Send the given result to client. This will stop all execution.
     200 *
     201 * @param       string  $id             Request id which was passed to the server in the request.
     202 * @param       array   $result Result of the request
     203 * @since       2.9.0
     204 * @return      void
     205 */
     206function wp_spellcheck_rpc_send_response($request_id, $result) {
     207
     208        // Request and response id should always be the same
     209        $output = array(
     210                "id" => $request_id,
     211                "result" => $result,
     212                "error" => null
     213        );
     214       
     215        // Return JSON encoded string
     216        echo wp_spellcheck_json_encode($output);
     217        exit();
     218}
     219
     220/**
     221 * Set headers for the spellcheck rpc response
     222 *
     223 * @uses        do_action       wp_spellcheck_rpc_headers
     224 * @since       2.9.0
     225 * @return      void
     226 */
     227function wp_spellcheck_rpc_response_headers() {
     228        header('Content-Type: text/plain');
     229        header('Content-Encoding: UTF-8');
     230        header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
     231        header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
     232        header("Cache-Control: no-store, no-cache, must-revalidate");
     233        header("Cache-Control: post-check=0, pre-check=0", false);
     234        header("Pragma: no-cache");     
     235       
     236        do_action('wp_spellcheck_rpc_headers');
     237}
     238
     239/**
     240 * Send json encoded error message to client. This will stop all execution.
     241 *
     242 * Note: this is a clone of TinyMCE's throwError() function in the
     243 * SpellChecker class (spellchecker plugin).
     244 *
     245 * @param       string  $msg    Message to send back to user.
     246 * @since       2.9.0
     247 * @return      void
     248 */
     249function wp_spellcheck_rpc_error($msg) {
     250        die('{"result":null,"id":null,"error":{"errstr":"' . addslashes($msg) . '","errfile":"","errline":null,"errcontext":"","level":"FATAL"}}');
     251}
     252
     253/**
     254 * Get the SpellChecker Engine Object
     255 *
     256 * @uses        apply_filters   wp_spellcheck_engine_class
     257 * @uses        apply_filters   wp_spellcheck_engine_path
     258 * @since       2.9.0
     259 * @return      SpellChecker    spell checking engine
     260 */
     261function &wp_spellcheck_get_engine() {
     262        static $spellchecker = null;
     263       
     264        if ($spellchecker === null) {
     265                // load base class for all spellcheckers
     266                if ( !class_exists('SpellChecker') ) {
     267                        require_once( MCE_SPELLCHECKER_DIR . "/classes/SpellChecker.php" );
     268                }
     269               
     270                $config = wp_spellcheck_get_engine_config();
     271               
     272                // get engine class name
     273                $engine_class = apply_filters('wp_spellcheck_engine_class', $config['general.engine']);
     274
     275                // try to load engine class if necessary
     276                if ( !class_exists($engine_class) ) {
     277
     278                        // determine engine file path
     279                        $engine_path = $config['general.engine.path'];
     280                        if (empty($engine_path)) {
     281                                $engine_path = MCE_SPELLCHECKER_DIR . "/classes/$engine_class.php";
     282                        }
     283                        $engine_path = apply_filters('wp_spellcheck_engine_path', $engine_path, $engine_class);
     284                       
     285                        if ( !file_exists($engine_path) ) {
     286                                return new WP_Error('wp-spellcheck-engine-not-found', __('Cannot load SpellChecker Engine; class file not found: ') . $engine_path );
     287                        }
     288                        require_once( $engine_path );
     289                       
     290                        if (!class_exists($engine_class)) {
     291                                return new WP_Error('wp-spellcheck-engine-not-found', __('Cannot load SpellChecker Engine; class not found: ') . $engine_class );
     292                        }
     293                }
     294               
     295                $spellchecker = new $engine_class($config);
     296        }
     297       
     298        return $spellchecker;
     299}
     300
     301/**
     302 * Get configuration values for the SpellChecker Engine.
     303 *
     304 * @uses        apply_filters   wp_spellcheck_engine_config
     305 * @since       2.9.0
     306 * @return      Array   array of config values
     307 */
     308function wp_spellcheck_get_engine_config() {
     309        $config = array();
     310        $config['general.engine'] = 'GoogleSpell';
     311       
     312        // load default tinymce config
     313        require_once( MCE_SPELLCHECKER_DIR . "/config.php" );
     314       
     315        return apply_filters('wp_spellcheck_engine_config', $config);
     316}
     317
     318/**
     319 * Encodes a php object into json
     320 *
     321 * @param       mixed   the thing to encode
     322 * @since       2.9.0
     323 * @return      string  json string
     324 */
     325function wp_spellcheck_json_encode($thing) {
     326        $json =& wp_spellcheck_json_object();
     327        return $json->encode($thing);
     328}
     329
     330/**
     331 * Decodes a json string into the respective php object
     332 *
     333 * @param       string  json string
     334 * @since       2.9.0
     335 * @return      mixed   json decoded thing
     336 */
     337function wp_spellcheck_json_decode($string) {
     338        $json =& wp_spellcheck_json_object();
     339        return $json->decode($string);
     340}
     341
     342/**
     343 * Returns an object of the moxiecode json encoder/transcoder class.
     344 *
     345 * @link http://core.trac.wordpress.org/browser/trunk/wp-includes/js/tinymce/plugins/spellchecker/classes/utils/JSON.php Moxiecode JSON Class
     346 * @since       2.9.0
     347 * @return      Moxiecode_JSON  JSON Encoder/Transcoder Object
     348 */
     349function &wp_spellcheck_json_object() {
     350        static $json = null;
     351        if ($json == null) {
     352                require_once( MCE_SPELLCHECKER_DIR . "/classes/utils/JSON.php" );
     353                $json = new Moxiecode_JSON();
     354        }
     355        return $json;
     356}
     357
     358?>
     359 No newline at end of file