Mon 25 Jun 2007
WordPress v2.2 spell checking problem
Posted by Dave under Administrative , Annoyances , Non-Perl , Win32So this entry isn’t about Perl but it is about a distant cousin, PHP, and the WordPress blogging software (v2.1+) spell checking bug that results in the notorious message:
Could not execute AJAX call, server didn’t return valid a XML
First let me start by saying that WordPress is a tremendous piece of software. I only have good things to say about it. Now that that is out of the way…
In WordPress v2.1+ there is a WYSIWYG option for writing posts, pages and comments. It isn’t full featured, but it is easy to use and provides the basics. It even includes a spell checker (which I am using as I write this). It is this spell checker that is causing so many people problems. When many people try to use the spell checker they receive the error message cited above. WordPress.org has a thread on this: http://wordpress.org/support/topic/101689
Having run into the same problem I decided to spend a couple of hours tracking down the problem and I can say that I have fixed it (on my system at least). My platform is running Windows Server 2003 with IIS and WordPress v2.2. I have patched my system and spell checker is working like a champ.
The Problem:
The nature of the problem has to do with a several things all coming together at once. The way that the spell checker is supposed to work is that it first checks for PHP’s built in spelling support called PSpell. In my case it looks like it has but when I try to use it I get Access Violation error (not a good sign). Failing that the spell checker will try to use the shell based PSpell library (in my case I had installed “ASpell.exe” on the server). I ensured that permissions were properly placed and that the IIS account could read/write the aspell files as well as temporary files. Failing all that the spell checker will then try to use Google’s online spell checker.
All of this spell checking is done using AJAX. If you are not familiar with AJAX, think of it as a way for a web page’s javascript code to call into a web server. The javascript spell checker calls into a URL on the server which calls the spelling library to look for misspelled words and make suggestions. The server returns this information and the javascript updates the web page by marking all misspelled words. To the user it looks like the web page did all the work — he doesn’t know that something called into the web server under the covers.
If something goes wrong with the AJAX all into the server you will get the error dialog. In my case there were several things that were going wrong:
- Only Google was being used.
My installation of PHP apparently has a problem with SSL. Somewhere in t bowels of the WordPress spell checker code that runs on the server it makes an SSL (HTTPS) call to Google’s spell checker web service. My PHP doesn’t recognize the SSL socket transport. Or at least that is what one error tells me. And since WordPress’ spell checker config.php file was set to only use Google, it would always fail. - PHP’s PSpell library wasn’t working.
Even though my PHP has built in support for PSpell enabling that option in the config.php file only led to an Access Violation error. Yes, I did copy the aspell-15.dll file into the path so that it could be located. And yes, I did enable the “extension=php_pspell.dll” line in the php.ini file. - The PSpell shell execution command was failing.
Even when I enabled the PSpellshell class (to shell out and run aspell.exe) spell checking failed. It ends up that the redirection of STDERR into STDIN for the shelled execution of aspell.exe was causing the problem. Hint: this is what I fixed!
The fix was to no longer shell out expecting the shell to redirect STDERR to STDIN. This often leads to problems on Windows machines. Instead use PHP’s proc_open() command to create the child process (aspell.exe) but use pipes for the process’ STDIN, STDOUT and STDERR. This way the code can read and write to the pipes and not worry about the pesky Windows shell.
The Solution:
To make a long story short I fixed the problem with the following. As always make backup files before you edit them in case all Hell breaks loose. You can download my modified versions of the 2 files described below: Updated TinyPspellShell.class.php and Updated config.php file. Note that you will need to rename these files to remove the trailing “.txt”.
Also note that these files came from WordPress v2.2 so they may need changes to fit into a v2.1 system.
- Edit wp-includes/js/tinymce/plugins/spellchecker/config.php
- Uncomment the line that loads TinyPspellShell.class.php
- Comment out the lines that load TinyPspell.class.php and TinyGoogle.class.php
- Change the value assigned to
$spellCheckerConfig['tinypspellshell.aspell']. Make it point to the actual aspell.exe such as:
$spellCheckerConfig['tinypspellshell.aspell'] = ‘”c:\program files\ASpell\bin\aspell.exe”‘;
- You can ignore the temporary file location since my fix eliminates the temporary files.
- Edit wp-includes/js/tinymce/plugins/spellchecker/classes/TinyPspellShell.class.php
- Perform a search on the file and locate the first line which assigns a value to
$this->cmd. Change it to be:
 Â$this->cmd = $config['tinypspellshell.aspell'] . ” -a –lang=”. $this->lang.” –encoding=utf-8 -H “;
Note that you do not have to touch the second line which assigns something to $this->cmd. This is for non Windows implementations (such as Linux). If you want you can try changing that line to:
  Â$this->cmd = $config['tinypspellshell.aspell'] . ” -a –encoding=utf-8 -H –lang=”. $this->lang;
Although have not tried this on a non Windows machine so I can not comment on how well it works. - Comment out the first block of code of the checkWords() function. Essentially you will be commenting out everything from the beginning of this function through the line:
@unlink($this->tmpfile);After the commented block of code place add the following line:
 Â$data = Win32Shell_Exec( $this->cmd, $wordArray ); - Comment out the following code from the getSuggestion() function:
 Âif ($fh = fopen($this->tmpfile, "w")) {
 fwrite($fh, "!\n");
 fwrite($fh, "^$word\n");
 fclose($fh);
 } else
 die("Error opening tmp file.");
 $data = shell_exec($this->cmd);
Now place the following line after the commented block of code:
$data = Win32Shell_Exec( $this->cmd, $word );
- At the end of the file add the following function:
- Perform a search on the file and locate the first line which assigns a value to
function Win32Shell_Exec( $Command, $WordObject )
{
 $descriptorspec = array(
 0 => array( “pipe”, “r”),
 1 => array(”pipe”, “w”), // stdout is a pipe that the child will write to
 2 => array(”file”, $TempFile . “.error-output”, “w”) // stderr is a file to write to
);
 $process = proc_open( $Command, $descriptorspec, $pipes);
 if( is_resource( $process ) )
 {
   $ProcessInputData = “”;
   // $pipes now looks like this:
   // 0 => writeable handle connected to child stdin
   // 1 => readable handle connected to child stdout
   // Any error output will be appended to /tmp/error-output.txt
   if( is_array( $WordObject ) )
   {
     $ProcessInputData = “!\n”;
     foreach( $WordObject as $Key => $Value)
     {
       $ProcessInputData .= “^” . $Value . “\n”;
     }
   }
   else
   {
     $ProcessInputData = “!\n^$WordObject\n”;
   }
   fwrite( $pipes[0], $ProcessInputData );
   fclose( $pipes[0] );
   while( !feof( $pipes[1] ) )
   {
     $myData .= fgets($pipes[1], 1024);
    }
    // It is important that you close any pipes before calling
   fclose($pipes[1]); // proc_close in order to avoid a deadlock
   $return_value = proc_close($process);
 }
 else
 {
   $myData = “COULD NOT CREATE PROCESS”;
 }
 return( $myData );
}
Don’t forget to properly install ASpell.exe and ensure that the IIS user account (typically something called IUSR_xxxx where xxx is the machine name) is granted read permission on the aspell directory.
 _EDIT_2007.09.30
This has been tested on both WordPress v2.2 and v2.3.
4 Responses to “WordPress v2.2 spell checking problem”
Leave a Reply
You must be logged in to post a comment.
November 1st, 2007 at 6:13 am
Will this work on a Linux server as well?
November 1st, 2007 at 8:34 am
It should, but I have not tested it. There is a line in TinyPspellShell.class.php that assigns a string used to launch the spell checker app. This string is assigned different values: one for Windows and one for Linux (reread the second bullet in the posting under “Solution”). It *should* work. If you do use Linux then you won’t need to make the Windows specific changes listed later in the TinyPspellShell.class.php file.
If you try it, let me know if it works.
January 18th, 2008 at 11:12 am
I’m trying desperatly to get this to work on Windows 2003 with IIS 6.0. I’ve followed the instructions precisely and now I have an error that reads “CreateProcess failed in [path]TinyPspellShell.class.php on line 136″ which is this line:
$process = proc_open( $Command, $descriptorspec, $pipes);
I have grabbed the contents of $Command and run it from a command line and it runs beautifully so I suspect an IIS setting or permission problem. Any suggestions?
January 22nd, 2008 at 12:47 pm
I ended up solving the problem by allowing Read and Execute permission to IUSR_xxxx on cmd.exe which is what is being used on the “CreateProcess”. Maybe this will help someone else out there.