/
Aspell.php
159 lines (135 loc) · 4.29 KB
/
Aspell.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
<?php
/**
* Copyright 2005-2015 Horde LLC (http://www.horde.org/)
*
* See the enclosed file COPYING for license information (LGPL). If you
* did not receive this file, see http://www.horde.org/licenses/lgpl21.
*
* @category Horde
* @copyright 2005-2015 Horde LLC
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
* @package SpellChecker
*/
/**
* A spellcheck driver for the aspell/ispell binary.
*
* @author Chuck Hagenbuch <chuck@horde.org>
* @author Michael Slusarz <slusarz@horde.org>
* @category Horde
* @copyright 2005-2015 Horde LLC
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
* @package SpellChecker
*/
class Horde_SpellChecker_Aspell extends Horde_SpellChecker
{
/**
* @param array $args Additional arguments:
* - path: (string) Path to the aspell binary.
*/
public function __construct(array $args = array())
{
parent::__construct(array_merge(array(
'path' => 'aspell'
), $args));
}
/**
*/
public function spellCheck($text)
{
$ret = array(
'bad' => array(),
'suggestions' => array()
);
if ($this->_params['html']) {
$input = strtr($text, "\n", ' ');
} else {
$words = $this->_getWords($text);
if (!count($words)) {
return $ret;
}
$input = implode(' ', $words);
}
// Descriptor array.
$descspec = array(
0 => array('pipe', 'r'),
1 => array('pipe', 'w'),
2 => array('pipe', 'w')
);
$process = proc_open($this->_cmd(), $descspec, $pipes);
if (!is_resource($process)) {
throw new Horde_SpellChecker_Exception('Spellcheck failed. Command line: ' . $this->_cmd());
}
// The '^' character tells aspell to spell check the entire line.
fwrite($pipes[0], '^' . $input);
fclose($pipes[0]);
// Read stdout.
$out = '';
while (!feof($pipes[1])) {
$out .= fread($pipes[1], 8192);
}
fclose($pipes[1]);
// Read stderr.
$err = '';
while (!feof($pipes[2])) {
$err .= fread($pipes[2], 8192);
}
fclose($pipes[2]);
// We can't rely on the return value of proc_close:
// http://bugs.php.net/bug.php?id=29123
proc_close($process);
if (strlen($out) === 0) {
throw new Horde_SpellChecker_Exception('Spellcheck failed. Command line: ' . $this->_cmd());
}
// Parse output.
foreach (array_map('trim', explode("\n", $out)) as $line) {
if (!strlen($line)) {
continue;
}
@list(,$word,) = explode(' ', $line, 3);
if ($this->_inLocalDictionary($word) ||
in_array($word, $ret['bad'])) {
continue;
}
switch ($line[0]) {
case '#':
// Misspelling with no suggestions.
$ret['bad'][] = $word;
$ret['suggestions'][] = array();
break;
case '&':
// Suggestions.
$ret['bad'][] = $word;
$ret['suggestions'][] = array_slice(explode(', ', substr($line, strpos($line, ':') + 2)), 0, $this->_params['maxSuggestions']);
break;
}
}
return $ret;
}
/**
* Create the command line string.
*
* @return string The command to run.
*/
protected function _cmd()
{
$args = array('-a', '--encoding=UTF-8');
switch ($this->_params['suggestMode']) {
case self::SUGGEST_FAST:
$args[] = '--sug-mode=fast';
break;
case self::SUGGEST_SLOW:
$args[] = '--sug-mode=bad-spellers';
break;
default:
$args[] = '--sug-mode=normal';
}
$args[] = '--lang=' . escapeshellarg($this->_params['locale']);
$args[] = '--ignore=' . escapeshellarg(max($this->_params['minLength'] - 1, 0));
if ($this->_params['html']) {
$args[] = '-H';
$args[] = '--rem-html-check=alt';
}
return escapeshellcmd($this->_params['path']) . ' ' .
implode(' ', $args);
}
}