forked from yodarunamok/fxphp
-
Notifications
You must be signed in to change notification settings - Fork 1
/
FX_Fuzzy_Debugger.php
268 lines (253 loc) · 13.5 KB
/
FX_Fuzzy_Debugger.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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
<?php
#### FX_Fuzzy_Debugger.php ##############################################
# #
# By: Chris Hansen #
# Version: 1.0 #
# Date: 25 Feb 2008 #
# License: Artistic License and addendum (included with release) #
# Web Site: www.iviking.org #
# Details: FX_Fuzzy_Debugger is part of the FX.php distribution. It #
# is designed to work with both FX.php and the FileMaker API #
# for PHP. For complete details about this class, please #
# visit www.iviking.org. #
# #
#########################################################################
require_once('Developer/FMErrors.php');
if (version_compare(phpversion(), '5.0') < 0) {
eval('
function clone($object) {
return $object;
}
');
}
define('FX_CONNECTION', 'FX');
define('FILEMAKER_API_CONNECTION', 'FAP');
class FX_Fuzzy_Debugger
{
var $ivikingContact = '[email protected]';
var $currentErrorCode = -2;
var $fixes = array();
var $currentConnection = null;
var $currentDataSet = null;
var $currentDatabase = '';
var $currentLayout = '';
var $currentFieldsArray = array();
var $connectionType = false;
var $fuzzyOut = false;
var $databasesArray = array();
var $layoutsArray = array();
var $fieldsArray = array();
var $similarityThreshold = 5;
function FX_Fuzzy_Debugger (&$fmConnection, &$dataSet='') // When using with the FileMaker API for PHP, pass both the connection, and the returned data set
{
if ((bool)(is_object($fmConnection) && (strtolower(get_class($fmConnection)) == 'filemaker' || is_subclass_of($fmConnection, 'filemaker')))) {
require_once('FileMaker.php');
$this->connectionType = FILEMAKER_API_CONNECTION;
$this->currentConnection = clone($fmConnection);
$this->currentDataSet = $dataSet;
if (FileMaker::isError($dataSet)) {
if (! isset($dataSet->code) || strlen(trim($dataSet->code)) < 1) {
$currentErrorMessage = "<p>A connection or XML error occured during your FileMaker query.<br />\n";
$currentErrorMessage .= "You may be able to get additional information by performing the same query using FX.php,<br />\n";
$currentErrorMessage .= "combined with a DEBUG constant and php's print_r() function.<br />\n";
$currentErrorMessage .= "Also, check your <strong>FileMaker Server Advanced configuration</strong>, and verify the <strong>server address</strong> used.</p>\n";
return $currentErrorMessage;
} else {
$this->currentErrorCode = $dataSet->code;
}
} else {
$this->currentErrorCode = 0;
}
$this->currentDatabase = $this->currentConnection->getProperty('database');
$this->currentLayout = '';
} elseif ((bool)(is_object($fmConnection) && (strtolower(get_class($fmConnection)) == 'fx' || is_subclass_of($fmConnection, 'fx')))) {
require_once('FX.php');
$this->connectionType = FX_CONNECTION;
$this->currentConnection = clone($fmConnection);
if (is_array($dataSet) && isset($dataSet['errorCode'])) {
$this->currentErrorCode = $dataSet['errorCode'];
} else {
$this->currentErrorCode = $fmConnection->lastErrorCode;
}
$this->currentDatabase = $this->currentConnection->database;
$this->currentLayout = $this->currentConnection->layout;
foreach ($this->currentConnection->lastQueryParams as $tempParam) {
if (substr($tempParam['name'], 0, 1) != '-') { // as long as the current field name doesn't begin with a '-' (FM reserved), add it to the list of fields
$this->currentFieldsArray[] = $tempParam['name'];
}
}
} else {
$currentErrorMessage = "<p>The FX Fuzzy Debugger does not support the type of connection that was passed in.<br />\n";
$currentErrorMessage .= "Double check that the first parameter is either an FX object or a FileMaker object.</p>\n";
$this->fuzzyOut = $currentErrorMessage;
return;
}
$this->fuzzyOut = $this->ProcessErrorCode();
}
function ProcessErrorCode ()
{
global $errorsList;
$errorTrapped = false;
$processingOutput = "<p>Begin FX Fuzzy Debugger Error processing...</p>";
$processingActionsArray = array();
$dbProcessor = 'CheckDBList';
$layoutProcessor = 'CheckLayoutsList';
$fieldProcessor = 'CheckFieldsList';
$processingOutput .= "<p>Error Code {$this->currentErrorCode}:<br />{$errorsList[$this->currentErrorCode]}</p>\n";
switch ($this->currentErrorCode) {
case -2:
$processingOutput .= "<p>No FX Action has been performed. Be sure to specify an action and try again.</p>\n";
break;
case -1:
$processingOutput .= "<p>This is officially an unknown error. If possible, please contact {$this->ivikingContact} with details.</p>\n";
break;
case 0:
return false;
break;
case 9: // insufficient privileges
$processingActionsArray = array($dbProcessor, $layoutProcessor);
$processingOutput .= "<p>Be sure that permissions are set properly. Pay special attention to any areas mentioned below.</p>\n";
break;
case 22: // (pseudo?) error returned (as far as I know) only by the FileMaker API for PHP
$processingOutput .= "<p>Observed only from the FileMaker API for PHP when a direct connection by FX.php to the FM Server would return other than XML.<br />\n";
$processingOutput .= "<p>Check the <strong>user name</strong> and <strong>password</strong> combination specified.</p>\n";
$processingOutput .= "<p>This error has not been observed when using FX.php; if this error was observed via an FX.php query, please contact {$this->ivikingContact} with details.</p>\n";
break;
case 102: // Field is missing
$processingActionsArray = array($fieldProcessor);
$processingOutput .= "<p>Double check the spelling of the fields specified, and be sure they're on the layout specified.<br />\n";
$processingOutput .= "Also, be sure that the <strong>user name</strong> and <strong>password</strong> combination specified has permission to access the specified fields.</p>\n";
// return $currentErrorMessage;
break;
case 105: // Layout Missing
$processingActionsArray = array($layoutProcessor);
$processingOutput .= "<p>Be sure that the <strong>user name</strong> and <strong>password</strong> combination specified has permission to access "{$this->currentLayout}".</p>\n";
break;
case 401: // No Records Found
$processingOutput .= "<p>This is a simple "No Records Found" error. Most likely, you just need to add trapping for situations where no records are found.</p>\n";
break;
case 802: // Unable to open file
$processingActionsArray = array($dbProcessor);
$processingOutput .= "<p>Be sure that you've specified the correct FileMaker Server address, that the server is running, and that the database specified is spelled correctly.<br />\n";
$processingOutput .= "Also, be sure that the credentials used have proper extended permissions associated with them.</p>\n";
break;
default:
$processingOutput .= "<p>This error is not yet supported within the FX Fuzzy Debugger. If possible, please contact {$this->ivikingContact} with details.</p>\n";
break;
}
foreach ($processingActionsArray as $key => $tempFuction) {
$tempFunctionReturn = call_user_func(array(&$this, $tempFuction));
if ($tempFunctionReturn !== true) {
if (is_array($tempFunctionReturn)) {
if (! is_array($tempFunctionReturn[0])) {
$tempFunctionReturn[0] = array($tempFunctionReturn[0]);
}
foreach ($tempFunctionReturn[0] as $tempDBElement) {
$nearestMatch = $this->FindNearestMatch($tempDBElement, $tempFunctionReturn[1]);
if ($nearestMatch === 0) {
$processingOutput .= "<p>Supposedly there wasn't a match for "{$tempDBElement}", but we found one. If possible, please contact {$this->ivikingContact} with details.</p>\n";
} elseif ($nearestMatch !== false) {
$processingOutput .= "<p>You entered "{$tempDBElement}", did you mean "{$nearestMatch}"?</p>\n";
} else {
$processingOutput .= "<p>No near matches were found for "{$tempDBElement}". The problem may be related to permissions.</p>\n";
}
}
} else {
$processingOutput .= $tempFunctionReturn;
}
break;
}
}
$processingOutput .= "<p>FX Fuzzy Debugger error processing finished.</p>";
return $processingOutput;
}
function CheckDBList ()
{
if (count($this->databasesArray) < 1) {
if ($this->connectionType == FILEMAKER_API_CONNECTION) {
$this->databasesArray = $this->currentConnection->listDatabases();
} elseif ($this->connectionType == FX_CONNECTION) {
$tempDBList = $this->currentConnection->DoFXAction('view_database_names');
foreach ($tempDBList as $value) {
$this->databasesArray[] = $value['DATABASE_NAME'];
}
} else {
return "<p>Unrecognized connection type when checking Databases.</p>";
}
}
if (array_search($this->currentDatabase, $this->databasesArray) !== false) {
return true;
} else {
return array($this->currentDatabase, $this->databasesArray);
}
}
function CheckLayoutsList ()
{
if (count($this->layoutsArray) < 1) {
if ($this->connectionType == FILEMAKER_API_CONNECTION) {
$this->layoutsArray = $this->currentConnection->listLayouts();
} elseif ($this->connectionType == FX_CONNECTION) {
$tempLayoutsList = $this->currentConnection->DoFXAction('view_layout_names');
foreach ($tempLayoutsList as $value) {
$this->layoutsArray[] = $value['LAYOUT_NAME'];
}
} else {
return "<p>Unrecognized connection type when checking Layouts.</p>";
}
}
if (array_search($this->currentLayout, $this->layoutsArray) !== false) {
return true;
} else {
return array($this->currentLayout, $this->layoutsArray);
}
}
function CheckFieldsList ()
{
$unknownFieldsArray = array();
if ($this->connectionType == FILEMAKER_API_CONNECTION) {
return "<p>The FileMaker API for PHP does not yet offer the functions needed to support detailed field name checking.</p>";
} elseif ($this->connectionType == FX_CONNECTION) {
$tempFieldsList = $this->currentConnection->DoFXAction('view_layout_objects');
foreach ($this->currentConnection->lastFields as $value) {
$this->fieldsArray[] = $value['name'];
}
} else {
return "<p>Unrecognized connection type when checking Fields.</p>";
}
foreach ($this->currentFieldsArray as $currentField) {
if (array_search($currentField, $this->fieldsArray) === false) {
$unknownFieldsArray[] = $currentField;
}
}
if (count($unknownFieldsArray) > 0) {
return array($unknownFieldsArray, $this->fieldsArray);
} else {
return true;
}
}
function FindNearestMatch ($currentItem, $searchArray)
{
$nearestDistance = -1;
$nearestMatch = false;
if (! is_array($searchArray)) { // if $searchArray isn't an array, it will cause us some grief...
return false;
}
foreach ($searchArray as $key => $tempItem) {
$tempDistance = levenshtein($currentItem, $tempItem);
if ($tempDistance == 0) {
return 0;
} elseif (($nearestDistance == -1 || $tempDistance < $nearestDistance) && $tempDistance <= $this->similarityThreshold) {
// we only update our match guess if the current option is closer _and_ we're within the specified threshold
$nearestDistance = $tempDistance;
$nearestMatch = $tempItem;
}
}
return $nearestMatch;
}
function SetSimilarityThreshold ($newThreshold)
{
$this->similarityThreshold = $newThreshold;
return true;
}
}
?>