Exponential 6.0.13 Exponential Enterprise Open Source CMS - PHP Class Reference

ezcodemapper.php
Go to the documentation of this file.
1 <?php
18 class eZCodeMapper
19 {
20 const TYPE_DIRECT = 1;
21 const TYPE_RANGE = 2;
22 const TYPE_REPLACE = 3;
23
24 public function __construct()
25 {
26 $this->TransformationTables = array();
27 $this->TransformationFiles = array();
28 }
29
33 function mappingTable( $identifier )
34 {
35 if ( isset( $this->TransformationTables[$identifier] ) )
36 return $this->TransformationTables[$identifier];
37 return false;
38 }
39
43 function ruleNames()
44 {
45 return array_keys( $this->TransformationTables );
46 }
47
51 function error( $text, $position = false )
52 {
53 if ( $position )
54 {
55 $str = $position['file'] . ':' . $position['from'][0] . ' C' . $position['from'][1];
56 if ( isset( $position['to'] ) )
57 $str .= ' -> L' . $position['to'][0] . ' C' . $position['to'][1];
58 $str .= ':';
59 }
60 $str .= $text;
61 if ( class_exists( 'ezcli' ) )
62 {
63 $cli = eZCLI::instance();
64 $cli->error( $str );
65 }
66 else
67 {
68 eZDebug::writeError( $str, __METHOD__ );
69 }
70 }
71
75 function warning( $text, $position = false )
76 {
77 if ( $position )
78 {
79 $str = $position['file'] . ':' . $position['from'][0] . ' C' . $position['from'][1];
80 if ( isset( $position['to'] ) )
81 $str .= ' -> L' . $position['to'][0] . ' C' . $position['to'][1];
82 $str .= ':';
83 }
84 $str .= $text;
85 if ( class_exists( 'ezcli' ) )
86 {
87 $cli = eZCLI::instance();
88 $cli->warning( $str );
89 }
90 else
91 {
92 eZDebug::writeWarning( $str, __METHOD__ );
93 }
94 }
95
99 function isTranformationLoaded( $name )
100 {
101 return in_array( $name, $this->TransformationFiles );
102 }
103
112 function loadTransformationFiles( $currentCharset, $transformationGroup )
113 {
114 $ini = eZINI::instance( 'transform.ini' );
115 $repositoryList = array( $ini->variable( 'Transformation', 'Repository' ) );
116 $files = $ini->variable( 'Transformation', 'Files' );
117 $extensions = $ini->variable( 'Transformation', 'Extensions' );
118 $repositoryList = array_merge( $repositoryList,
119 eZExtension::expandedPathList( $extensions, 'transformations' ) );
120
121 // Check if the current charset maps to a unicode group
122 // If it does it can trigger loading of additional files
123 $unicodeGroups = array();
124 $charsets = $ini->variable( 'Transformation', 'Charsets' );
125 foreach ( $charsets as $entry )
126 {
127 list ( $charset, $group ) = explode( ';', $entry, 2 );
128 $charset = eZCharsetInfo::realCharsetCode( $charset );
129 if ( $charset == $currentCharset )
130 {
131 if ( !in_array( $group, $unicodeGroups ) )
132 $unicodeGroups[] = $group;
133 }
134 }
135
136 // If we are using transformation groups then add that as
137 // a unicode group. This causes it load transformation files
138 // specific to that group.
139 if ( $transformationGroup !== false )
140 $unicodeGroups[] = $transformationGroup;
141
142 // Add any extra files from the unicode groups
143 foreach ( $unicodeGroups as $unicodeGroup )
144 {
145 if ( $ini->hasGroup( $unicodeGroup ) )
146 {
147 $files = array_merge( $files, $ini->variable( $unicodeGroup, 'Files' ) );
148 $extensions = $ini->variable( $unicodeGroup, 'Extensions' );
149 $repositoryList = array_merge( $repositoryList,
150 eZExtension::expandedPathList( $extensions, 'transformations' ) );
151 }
152 }
153
154 foreach ( $files as $file )
155 {
156 // Only load files that are not currently loaded
157 if ( $this->isTranformationLoaded( $file ) )
158 continue;
159
160 foreach ( $repositoryList as $repository )
161 {
162 $trFile = $repository . '/' . $file;
163 if ( file_exists( $trFile ) )
164 {
165 $this->parseTransformationFile( $trFile, $file );
166 }
167 }
168 }
169 }
170
176 function parseTransformationFile( $filename, $name )
177 {
178 // eZDebug::writeDebug( "Parsing file $filename" );
179 $tbl = array();
180
181 $fd = fopen( $filename, "rb" );
182 if ( !$fd )
183 {
184 $this->error( "Failed opening $filename" );
185 return false;
186 }
187
188 $this->TransformationFiles[] = $name;
189
190 $this->ISOUnicodeCodec = eZTextCodec::instance( 'iso-8859-1', 'unicode' );
191
192 $buffer = '';
193 $lineNum = 1;
194 $i = 0;
195 $hexValues = "0123456789abcdefABCDEF";
196 $identifier = false;
197
198 // The big funky parser starts here
199 // It starts by reading a chunk of data from the file
200 // then splits everything into an array with lines.
201 // Then it traverses one line at a time looking for
202 // identifiers and rules. Comments will be removed before the
203 // line is parsed for identifiers and rules.
204
205 while ( !feof( $fd ) or strlen( $buffer ) > 0 )
206 {
207 $lines = array();
208 $len = strlen( $buffer );
209 // Check if we have data in the buffer yet
210 // Note: The actual buffer reading is done at the end of this while loop
211 if ( $len > 0 )
212 {
213 $endPos = false;
214 $eolPos = 0;
215 // Look for complete lines and append to $lines
216 while ( $eolPos !== false and $eolPos < $len )
217 {
218 $eolPos = strpos( $buffer, "\n", $endPos );
219 if ( $eolPos !== false )
220 {
221 $line = substr( $buffer, $endPos, $eolPos - $endPos );
222 $lines[] = array( 'text' => $line,
223 'line' => $lineNum );
224 ++$lineNum;
225 $endPos = $eolPos + 1;
226 }
227 }
228
229 // If we have leftover data place that back in $buffer
230 if ( $endPos !== false )
231 {
232 $buffer = substr( $buffer, $endPos );
233 }
234 }
235
236 // Once we have some lines start parsing them one at a time
237 foreach ( $lines as $lineData )
238 {
239 $line = $lineData['text'];
240 $lineOrg = $line;
241 $linePos = $lineData['line'];
242 $commentPos = strpos( $line, '#' );
243 $origLine = $line;
244 // Get rid of any comments before we check the line
245 if ( $commentPos !== false )
246 {
247 $line = substr( $line, 0, $commentPos );
248 }
249 $trimLine = trim( $line );
250 // Skip empty lines
251 if ( strlen( $trimLine ) == 0 )
252 continue;
253
254 // print( "Line: '$line'\n" );
255
256 $unicodeData = false;
257
258 $sourceValue = false;
259 $sourceEndValue = false;
260 $destinationValues = false;
261 $transposeValue = false;
262 $transposeAdd = true;
263 $moduloValue = 1;
264 // source, marker, range_input, range_marker, map_input, transpose_input, replace_input
265 $state = 'source';
266 // map, transpose, replace
267 $type = false;
268
269 $len = strlen( $line );
270 if ( preg_match( '#^(.+):[ \t]*$#', $line, $matches ) )
271 {
272 $identifier = $matches[1];
273 if ( !preg_match( '#^[a-zA-Z_-][a-zA-Z0-9_-]*$#', $identifier ) )
274 {
275 $this->warning( "Invalid identifier '$identifier', can only contain a-z, a-Z - and _",
276 array( 'file' => $filename, 'from' => array( $linePos, strlen( $identifier ) ) ) );
277 $identifier = false;
278 continue;
279 }
280 // print( "identifier '$identifier'\n" );
281 continue;
282 }
283 else if ( $identifier === false )
284 {
285 $this->warning( "No identifier defined yet, skipping: '" . $line . "'",
286 array( 'file' => $filename, 'from' => array( $linePos, 0 ) ) );
287 continue;
288 }
289 else
290 {
291 $pos = 0;
292 $col = 0;
293 $failed = false;
294 while ( $pos < $len )
295 {
296 while ( $pos < $len and
297 ( $line[$pos] == ' ' or
298 $line[$pos] == "\t" ) )
299 {
300 ++$pos;
301 }
302 if ( $pos >= $len )
303 break;
304
305 $char = $line[$pos];
306 $unicodeData = false;
307 if ( $char == '"' )
308 {
309 $delimiterPos = $pos;
310 while ( $delimiterPos < $len )
311 {
312 $delimiterPos = strpos( $line, '"', $delimiterPos + 1 );
313 if ( $delimiterPos === false or
314 $delimiterPos <= $pos + 1 or
315 $line[$delimiterPos - 1] != "\\" )
316 break;
317 }
318 if ( $delimiterPos === false )
319 {
320 $this->warning( "No end-quote found for line, skipping: '$line'",
321 array( 'file' => $filename,
322 'from' => array( $linePos, $pos ),
323 'to' => array( $linePos, strlen( $line ) ) ) );
324 $pos = $len;
325 $failed = true;
326 break;
327 }
328 $str = str_replace( array( "\\\"", "\\\\" ),
329 array( "\"", "\\" ),
330 substr( $line, $pos + 1, $delimiterPos - $pos - 1 ) );
331 // print( "string '$str'\n" );
332 $pos = $delimiterPos + 1;
333 $unicodeData = array( 'value' => $str,
334 'type' => 'string' );
335 }
336 else if ( $char == 'U' and
337 $pos + 1 < $len and
338 $line[$pos + 1] == '+' )
339 {
340 $hexPos = $pos + 2;
341 if ( $hexPos + 4 > $len )
342 {
343 $col = $hexPos;
344 $this->warning( "Found U+ value with " . ( 4 - ( $len - $hexPos ) ) . " missing hex numbers",
345 array( 'file' => $filename,
346 'from' => array( $linePos, $hexPos ) ) );
347 $failed = true;
348 $pos = $hexPos;
349 break;
350 }
351 $hasHexValues = true;
352 for ( $offset = 0; $offset < 4; ++$offset )
353 {
354 $hexChar = $line[$hexPos + $offset];
355 if ( $hexChar == ' ' or
356 $hexChar == "\t" )
357 {
358 $col = $hexPos + $offset;
359 $hasHexValues = false;
360 $this->warning( "Found U+ value with " . ( 4 - $offset ) . " missing hex numbers",
361 array( 'file' => $filename,
362 'from' => array( $linePos, $hexPos ),
363 'to' => array( $linePos, $hexPos + $offset ) ) );
364 $failed = true;
365 $pos = $hexPos + $offset;
366 break;
367 }
368 if ( strpos( $hexValues, $hexChar ) === false )
369 {
370 $col = $hexPos + $offset;
371 $hasHexValues = false;
372 $this->warning( "Found U+ value with invalid hex numbers ($hexChar)",
373 array( 'file' => $filename,
374 'from' => array( $linePos, $hexPos ),
375 'to' => array( $linePos, $hexPos + $offset ) ) );
376 $pos = $hexPos + $offset;
377 $failed = true;
378 break;
379 }
380 }
381 if ( $failed )
382 break;
383 if ( $hasHexValues )
384 {
385 $unicodeValue = hexdec( substr( $line, $hexPos, 4 ) );
386 $unicodeData = array( 'value' => $unicodeValue,
387 'type' => 'unicode' );
388 // print( "unicode U+ '$unicodeValue'\n" );
389 }
390 $pos = $hexPos + 4;
391 }
392 else if ( strpos( $hexValues, $char ) !== false and
393 $pos + 1 < $len and
394 strpos( $hexValues, $line[$pos + 1] ) !== false )
395 {
396 $hexPos = $pos;
397 if ( $hexPos + 2 > $len )
398 {
399 $col = $len;
400 $this->warning( "Found ASCII value with " . ( 2 - ( $len - $hexPos ) ) . " missing hex numbers",
401 array( 'file' => $filename,
402 'from' => array( $linePos, $hexPos ) ) );
403 $pos = $hexPos;
404 $failed = true;
405 break;
406 }
407 $hasHexValues = true;
408 for ( $offset = 0; $offset < 2; ++$offset )
409 {
410 $hexChar = $line[$hexPos + $offset];
411 if ( $hexChar == ' ' or
412 $hexChar == "\t" )
413 {
414 $col = $hexPos + $offset;
415 $hasHexValues = false;
416 $this->warning( "Found ASCII value with " . ( 2 - $offset ) . " missing hex numbers",
417 array( 'file' => $filename,
418 'from' => array( $linePos, $hexPos ),
419 'to' => array( $linePos, $hexPos + $offset ) ) );
420 $pos = $hexPos + $offset;
421 $failed = true;
422 break;
423 }
424 if ( strpos( $hexValues, $hexChar ) === false )
425 {
426 $col = $hexPos + $offset;
427 $hasHexValues = false;
428 $this->warning( "Found ASCII value with invalid hex numbers ($hexChar)",
429 array( 'file' => $filename,
430 'from' => array( $linePos, $hexPos ),
431 'to' => array( $linePos, $hexPos + $offset ) ) );
432 $pos = $hexPos + $offset;
433 $failed = true;
434 break;
435 }
436 }
437 if ( $failed )
438 break;
439 if ( $hasHexValues )
440 {
441 $asciiValue = hexdec( substr( $line, $hexPos, 4 ) );
442 // print( "unicode ASCII '$asciiValue'\n" );
443 $unicodeData = array( 'value' => $asciiValue,
444 'type' => 'ascii' );
445 }
446 $pos = $hexPos + 2;
447 }
448 else if ( substr( $line, $pos, 6 ) == 'remove' )
449 {
450 // print( "remove character\n" );
451 $unicodeData = array( 'value' => false,
452 'type' => 'remove' );
453 $pos += 6;
454 }
455 else if ( substr( $line, $pos, 4 ) == 'keep' )
456 {
457 // print( "keep character\n" );
458 $unicodeData = array( 'value' => true,
459 'type' => 'keep' );
460 $pos += 4;
461 }
462
463 if ( $unicodeData )
464 {
465 // print( "data state: $state\n" );
466 // source, marker, range_input, range_marker, map_input, transpose_input, replace_input, transpose_modulo
467 if ( $state == 'source' )
468 {
469 if ( $unicodeData['type'] == 'string' and
470 strlen( $unicodeData['value'] ) > 1 )
471 {
472 $this->warning( "Text string with more than one character cannot be used as input value '" . $unicodeData['value'] . "'",
473 array( 'file' => $filename,
474 'from' => array( $linePos, $pos ) ) );
475 $failed = true;
476 break;
477 }
478 $sourceValue = $this->extractUnicodeValue( $unicodeData );
479 $state = 'marker';
480 }
481 else if ( $state == 'marker' )
482 {
483 $this->warning( "Source value not expected, a source value has already been extracted at $line" . "[$pos]",
484 array( 'file' => $filename,
485 'from' => array( $linePos, $pos ) ) );
486 $failed = true;
487 break;
488 }
489 else if ( $state == 'range_input' )
490 {
491 if ( $unicodeData['type'] == 'string' and
492 strlen( $unicodeData['value'] ) > 1 )
493 {
494 $this->warning( "Text string with more than one character cannot be used as range end value '" . $unicodeData['value'] . "'",
495 array( 'file' => $filename,
496 'from' => array( $linePos, $pos ) ) );
497 $failed = true;
498 break;
499 }
500 $sourceEndValue = $this->extractUnicodeValue( $unicodeData );
501 $state = 'range_marker_or_modulo';
502 }
503 else if ( $state == 'range_marker_or_modulo' or
504 $state == 'range_marker' )
505 {
506 $this->warning( "Range value not expected, a range value has already been extracted at $line" . "[$pos]",
507 array( 'file' => $filename,
508 'from' => array( $linePos, $pos ) ) );
509 $failed = true;
510 break;
511 }
512 else if ( $state == 'map_input' )
513 {
514 if ( !is_array( $destinationValues ) )
515 $destinationValues = array();
516 $destinationValues = array_merge( $destinationValues,
517 $this->extractUnicodeValues( $unicodeData ) );
518 $type = 'map';
519 }
520 else if ( $state == 'replace_input' )
521 {
522 if ( !is_array( $destinationValues ) )
523 $destinationValues = array();
524 $destinationValues = array_merge( $destinationValues,
525 $this->extractUnicodeValues( $unicodeData ) );
526 $type = 'replace';
527 }
528 else if ( $state == 'transpose_input' )
529 {
530 if ( $unicodeData['type'] == 'string' and
531 strlen( $unicodeData['value'] ) > 1 )
532 {
533 $this->warning( "Text string with more than one character cannot be used as transpose value '" . $unicodeData['value'] . "'",
534 array( 'file' => $filename,
535 'from' => array( $linePos, $pos ) ) );
536 $failed = true;
537 break;
538 }
539 $transposeValue = $this->extractUnicodeValue( $unicodeData );
540 $type = 'transpose';
541 }
542 else if ( $state == 'transpose_modulo' )
543 {
544 if ( $unicodeData['type'] == 'string' and
545 strlen( $unicodeData['value'] ) > 1 )
546 {
547 $this->warning( "Text string with more than one character cannot be used as transpose modulo value '" . $unicodeData['value'] . "'",
548 array( 'file' => $filename,
549 'from' => array( $linePos, $pos ) ) );
550 $failed = true;
551 break;
552 }
553 $moduloValue = $this->extractUnicodeValue( $unicodeData );
554 if ( $moduloValue == 0 )
555 {
556 $this->error( "Modulo value of 0 is not allowed, 1 will be used instead",
557 array( 'file' => $filename,
558 'from' => array( $linePos, $pos ) ) );
559 // Note: There is another 0 check in generateSimpleMappingTable()
560 }
561 // print( "modulo value=$moduloValue\n" );
562 $state = 'range_marker';
563 }
564 }
565 else if ( !$failed )
566 {
567 // print( "command state: $state\n" );
568 // source, marker, range_input, range_marker, map_input, transpose_input, replace_input
569 if ( $state == 'source' )
570 {
571 if ( $char == '=' )
572 {
573 $this->warning( "Cannot use map marker $char without prior character value",
574 array( 'file' => $filename,
575 'from' => array( $linePos, $pos ) ) );
576 $failed = true;
577 break;
578 }
579 else if ( $char == '+' or
580 $char == '-' )
581 {
582 $this->warning( "Cannot use range marker $char without prior character value",
583 array( 'file' => $filename,
584 'from' => array( $linePos, $pos ) ) );
585 $failed = true;
586 break;
587 }
588 else
589 {
590 $this->warning( "Unknown character '$char', expecting input value",
591 array( 'file' => $filename,
592 'from' => array( $linePos, $pos ) ) );
593 $failed = true;
594 break;
595 }
596 }
597 else if ( $state == 'marker' )
598 {
599 if ( $char == '=' )
600 {
601 $state = 'map_input';
602 ++$pos;
603 }
604 else if ( $char == '-' )
605 {
606 $state = 'range_input';
607 ++$pos;
608 }
609 else if ( $char == '+' )
610 {
611 $this->warning( "Cannot use range marker $char without prior character value",
612 array( 'file' => $filename,
613 'from' => array( $linePos, $pos ) ) );
614 $failed = true;
615 break;
616 }
617 else
618 {
619 $this->warning( "Unknown character '$char', expecting marker",
620 array( 'file' => $filename,
621 'from' => array( $linePos, $pos ) ) );
622 $failed = true;
623 break;
624 }
625 }
626 else if ( $state == 'range_marker_or_modulo' or
627 $state == 'range_marker' )
628 {
629 if ( $state == 'range_marker_or_modulo' and
630 $char == '%' )
631 {
632 // print( "found modulo marker\n" );
633 // Look for modulo value
634 $state = 'transpose_modulo';
635 ++$pos;
636 }
637 else if ( $char == '=' )
638 {
639 $state = 'replace_input';
640 ++$pos;
641 }
642 else if ( $char == '-' or
643 $char == '+' )
644 {
645 $transposeAdd = ( $char == '+' ? true : false );
646 $state = 'transpose_input';
647 ++$pos;
648 }
649 else
650 {
651 $this->warning( "Unknown character '$char', expecting range end value",
652 array( 'file' => $filename,
653 'from' => array( $linePos, $pos ) ) );
654 $failed = true;
655 break;
656 }
657 }
658 else if ( $state == 'map_input' )
659 {
660 if ( $char == '=' )
661 {
662 $this->warning( "Duplicate mapping marker $char",
663 array( 'file' => $filename,
664 'from' => array( $linePos, $pos ) ) );
665 $failed = true;
666 break;
667 }
668 else if ( $char == '-' or
669 $char == '+' )
670 {
671 $this->warning( "Already mapping values, cannot use range/transpose marker $char",
672 array( 'file' => $filename,
673 'from' => array( $linePos, $pos ) ) );
674 $failed = true;
675 break;
676 }
677 else
678 {
679 $this->warning( "Unknown character '$char', expecting output values",
680 array( 'file' => $filename,
681 'from' => array( $linePos, $pos ) ) );
682 $failed = true;
683 break;
684 }
685 }
686 else if ( $state == 'transpose_modulo' )
687 {
688 if ( $char == '%' )
689 {
690 $this->warning( "Modulo marker already used, cannot use $char",
691 array( 'file' => $filename,
692 'from' => array( $linePos, $pos ) ) );
693 $failed = true;
694 break;
695 }
696 else if ( $char == '-' or
697 $char == '+' )
698 {
699 $this->warning( "Transpose marker $char used, but no modulo value has been found yet",
700 array( 'file' => $filename,
701 'from' => array( $linePos, $pos ) ) );
702 $failed = true;
703 break;
704 }
705 else
706 {
707 $this->warning( "Unknown character '$char', expecting modulo value",
708 array( 'file' => $filename,
709 'from' => array( $linePos, $pos ) ) );
710 $failed = true;
711 break;
712 }
713 }
714 else if ( $state == 'transpose_input' )
715 {
716 if ( $char == '=' )
717 {
718 $this->warning( "Already transposing, cannot use mapping marker $char",
719 array( 'file' => $filename,
720 'from' => array( $linePos, $pos ) ) );
721 $failed = true;
722 break;
723 }
724 else if ( $char == '-' or
725 $char == '+' )
726 {
727 $this->warning( "Duplicate transpose marker $char",
728 array( 'file' => $filename,
729 'from' => array( $linePos, $pos ) ) );
730 $failed = true;
731 break;
732 }
733 else
734 {
735 $this->warning( "Unknown character '$char', expecting transpose value",
736 array( 'file' => $filename,
737 'from' => array( $linePos, $pos ) ) );
738 $failed = true;
739 break;
740 }
741 }
742 else if ( $state == 'replace_input' )
743 {
744 if ( $char == '=' )
745 {
746 $this->warning( "Already replacing, cannot use mapping marker $char",
747 array( 'file' => $filename,
748 'from' => array( $linePos, $pos ) ) );
749 $failed = true;
750 break;
751 }
752 else if ( $char == '-' or
753 $char == '+' )
754 {
755 $this->warning( "Already replacing, cannot use transpose marker $char",
756 array( 'file' => $filename,
757 'from' => array( $linePos, $pos ) ) );
758 $failed = true;
759 break;
760 }
761 else
762 {
763 $this->warning( "Unknown character '$char', expecting replace value",
764 array( 'file' => $filename,
765 'from' => array( $linePos, $pos ) ) );
766 $failed = true;
767 break;
768 }
769 }
770 }
771 }
772 if ( !$failed )
773 {
774 if ( $identifier )
775 {
776 // print( "\nGot type '$type'\n" );
777 // if ( is_array( $destinationValues ) )
778 // $destinationValues = array_diff( $destinationValues, array( '' ) );
779
780 if ( !isset( $tbl[$identifier] ) )
781 $tbl[$identifier] = array();
782
783 if ( $type == 'map' )
784 {
785 // print( "***mapping***:\n" . $sourceValue . ' => ' . implode( ', ', $destinationValues ) . "\n\n" );
786 $this->appendDirectMapping( $tbl[$identifier], $identifier, $sourceValue, $destinationValues );
787 }
788 else if ( $type == 'replace' )
789 {
790 // print( "***replacing***:\n" . $sourceValue . ' - ' . $sourceEndValue . ' => ' . implode( ', ', $destinationValues ) . "\n\n" );
791 $this->appendReplaceMapping( $tbl[$identifier], $identifier, $sourceValue, $sourceEndValue, $destinationValues );
792 }
793 else if ( $type == 'transpose' )
794 {
795 // print( "***transposing***:\n" . $sourceValue . ' - ' . $sourceEndValue . ' % ' . $moduloValue . ' + ' . $transposeValue . "\n\n" );
796 $this->appendTransposeMapping( $tbl[$identifier], $identifier, $sourceValue, $sourceEndValue, $transposeValue, $transposeAdd, $moduloValue );
797 }
798 }
799 // else
800 // {
801 // print( "No identifier found yet, skipping entry!!!!!!!!!!\n" );
802 // }
803 }
804 else
805 {
806 // $this->warning( "Failed adding mapper",
807 // array( 'file' => $filename,
808 // 'from' => array( $linePos, $pos ) ) );
809 }
810 }
811 }
812
813 // Here we read more data from the file, appending to
814 // the $buffer variable
815 if ( !feof( $fd ) )
816 {
817 $buffer .= fread( $fd, 4096 );
818
819 // Make sure we have Unix endline characters
820 $buffer = preg_replace( "#(\r\n|\r|\n)#", "\n", $buffer );
821 }
822 ++$i;
823 }
824
825 fclose( $fd );
826
827 $this->TransformationTables = array_merge( $this->TransformationTables, $tbl );
828 }
829
838 function appendDirectMapping( &$block, $identifier, $sourceValue, $destinationValues )
839 {
840 $count = count( $block );
841 if ( count( $destinationValues ) == 1 )
842 $destinationValues = array_pop( $destinationValues );
843 if ( isset( $block[$count - 1] ) and
844 $block[$count - 1][0] == self::TYPE_DIRECT and
845 $block[$count - 1][2] == $identifier )
846 {
847 $block[$count - 1][1][$sourceValue] = $destinationValues;
848 }
849 else
850 {
851 $block[] = array( self::TYPE_DIRECT,
852 array( $sourceValue => $destinationValues ),
853 $identifier );
854
855 }
856 }
857
867 function appendReplaceMapping( &$block, $identifier, $sourceValue, $sourceEndValue, $destinationValues )
868 {
869 $count = count( $block );
870 if ( count( $destinationValues ) == 1 )
871 $destinationValues = array_pop( $destinationValues );
872 if ( isset( $block[$count - 1] ) and
873 $block[$count - 1][0] == self::TYPE_REPLACE and
874 $block[$count - 1][2] == $identifier )
875 {
876 $block[$count - 1][1][] = array( $sourceValue, $sourceEndValue, $destinationValues );
877 }
878 else
879 {
880 $block[] = array( self::TYPE_REPLACE,
881 array( array( $sourceValue, $sourceEndValue, $destinationValues ) ),
882 $identifier );
883
884 }
885 }
886
897 function appendTransposeMapping( &$block, $identifier, $sourceValue, $sourceEndValue, $transposeValue, $addValue, $moduloValue )
898 {
899 $count = count( $block );
900 if ( isset( $block[$count - 1] ) and
901 $block[$count - 1][0] == self::TYPE_RANGE and
902 $block[$count - 1][2] == $identifier )
903 {
904 $block[$count - 1][1][] = array( $sourceValue, $sourceEndValue, $addValue ? $transposeValue : -$transposeValue, $moduloValue );
905 }
906 else
907 {
908 $block[] = array( self::TYPE_RANGE,
909 array( array( $sourceValue, $sourceEndValue, $addValue ? $transposeValue : -$transposeValue, $moduloValue ) ),
910 $identifier );
911
912 }
913 }
914
919 function extractUnicodeValue( $data )
920 {
921 $type = $data['type'];
922 if ( $type == 'string' )
923 {
924 $list = $this->ISOUnicodeCodec->convertString( $data['value'][0] );
925 return $list[0];
926 }
927 else if ( $type == 'ascii' )
928 {
929 return $data['value'];
930 }
931 else if ( $type == 'unicode' )
932 {
933 return $data['value'];
934 }
935 else if ( $type == 'remove' )
936 {
937 return false;
938 }
939 else if ( $type == 'keep' )
940 {
941 return true;
942 }
943 return null;
944 }
945
950 function extractUnicodeValues( $data )
951 {
952 $type = $data['type'];
953 if ( $type == 'string' )
954 {
955 return $this->ISOUnicodeCodec->convertString( $data['value'] );
956 }
957 else if ( $type == 'ascii' )
958 {
959 return array( $data['value'] );
960 }
961 else if ( $type == 'unicode' )
962 {
963 return array( $data['value'] );
964 }
965 else if ( $type == 'remove' )
966 {
967 return array( false );
968 }
969 else if ( $type == 'keep' )
970 {
971 return array( true );
972 }
973 return array();
974 }
975
982 function expandInheritance( $table )
983 {
984 $newTable = array();
985 foreach ( $table as $tableItem )
986 {
987 if ( is_string( $tableItem ) )
988 {
989 $identifier = $tableItem;
990 $subTable = $this->mappingTable( $identifier );
991 if ( !$subTable )
992 {
993 eZDebug::writeError( "Failed to fetch mapping table for identifier: '$identifier'" );
994 }
995 else
996 {
997 $subTable = $this->expandInheritance( $subTable );
998 $newTable = array_merge( $newTable, $subTable );
999 }
1000 }
1001 else
1002 {
1003 $newTable[] = $tableItem;
1004 }
1005 }
1006 return $newTable;
1007 }
1008
1017 function ordinalValues( $table, $list )
1018 {
1019 $ordinals = array();
1020 if ( is_string( $list ) )
1021 {
1022 $len = strlen( $list );
1023 for ( $offset = 0; $offset < $len; ++$offset )
1024 {
1025 $ordinals[] = ord( $list[$offset] );
1026 }
1027 }
1028 else if ( is_numeric( $list ) )
1029 {
1030 $ordinals[] = $list;
1031 }
1032 else if ( is_array( $list ) )
1033 {
1034 foreach ( $list as $item )
1035 {
1036 $ordinals = array_merge( $ordinals, eZCodeMapper::ordinalValues( $table, $item ) );
1037 }
1038 }
1039 $ordinals = eZCodeMapper::mapOrdinals( $table, $ordinals );
1040 return $ordinals;
1041 }
1042
1048 function mapOrdinals( $table, $ordinals )
1049 {
1050 $mappedOrdinals = array();
1051 foreach ( $ordinals as $ordinal )
1052 {
1053 while ( !is_array( $ordinal ) and isset( $table[$ordinal] ) )
1054 {
1055 $ordinal = $table[$ordinal];
1056 if ( is_array( $ordinal ) )
1057 {
1058 $ordinal = eZCodeMapper::mapOrdinals( $table, $ordinal );
1059 }
1060 }
1061 if ( is_array( $ordinal ) )
1062 $mappedOrdinals = array_merge( $mappedOrdinals, $ordinal );
1063 else
1064 $mappedOrdinals[] = $ordinal;
1065 }
1066 return $mappedOrdinals;
1067 }
1068
1075 protected function mapExistingCodes( $unicodeMap, $fromCode, $toCode )
1076 {
1077 foreach ( $unicodeMap as $from => $to )
1078 {
1079 if ( is_array( $to ) )
1080 {
1081 $newTo = array();
1082 foreach ( $to as $ordinal )
1083 {
1084 if ( $ordinal == $fromCode )
1085 {
1086 $newTo = array_merge( $newTo, array( $toCode ) );
1087 }
1088 else
1089 {
1090 $newTo[] = $ordinal;
1091 }
1092 }
1093 $unicodeMap[$from] = $newTo;
1094 }
1095 else if ( $to == $fromCode )
1096 {
1097 $unicodeMap[$from] = $toCode;
1098 }
1099 }
1100 return $unicodeMap;
1101 }
1102
1112 function generateSimpleMappingTable( $table, $allowedRanges )
1113 {
1114 if ( !is_array( $table ) )
1115 return false;
1116 $unicodeMap = array();
1117 foreach ( $table as $tableItem )
1118 {
1119 $type = $tableItem[0];
1120 $item = $tableItem[1];
1121 if ( isset( $tableItem[2] ) )
1122 {
1123 $identifier = $tableItem[2];
1124 // print( "identifier: $identifier\n" );
1125 }
1126 if ( $type == self::TYPE_DIRECT )
1127 {
1128 foreach ( $item as $fromCode => $toCode )
1129 {
1130 // print( "from: $fromCode, to: $toCode\n" );
1131 // if ( $fromCode == 1026 )
1132 // {
1133 // print( "<pre>oldcode<br/>" ); var_dump( $toCode ); print( "</pre>" );
1134 // }
1135 $toCode = eZCodeMapper::ordinalValues( $unicodeMap, $toCode );
1136 // if ( $fromCode == 1026 )
1137 // {
1138 // print( "<pre>newcode<br/>" ); var_dump( $toCode ); print( "</pre>" );
1139 // }
1140 if ( count( $allowedRanges ) == 0 )
1141 {
1142 if ( count( $toCode ) == 1 )
1143 $toCode = $toCode[0];
1144 // If the mapping already exists we skip it
1145 if ( isset( $unicodeMap[$fromCode] ) )
1146 continue;
1147
1148 $unicodeMap[$fromCode] = $toCode;
1149 $unicodeMap = eZCodeMapper::mapExistingCodes( $unicodeMap, $fromCode, $toCode );
1150 }
1151 else
1152 {
1153 $allowed = false;
1154 foreach ( $allowedRanges as $allowedRange )
1155 {
1156 if ( $fromCode >= $allowedRange[0] and
1157 $fromCode <= $allowedRange[1] )
1158 {
1159 $allowed = true;
1160 break;
1161 }
1162 }
1163 if ( !$allowed )
1164 continue;
1165
1166 $toCodeList = $toCode;
1167 $newToCodeList = array();
1168 foreach ( $toCodeList as $toCode )
1169 {
1170 if ( is_bool( $toCode ) )
1171 {
1172 $newToCodeList[] = $toCode;
1173 continue;
1174 }
1175 foreach ( $allowedRanges as $allowedRange )
1176 {
1177 if ( $toCode >= $allowedRange[0] and
1178 $toCode <= $allowedRange[1] )
1179 {
1180 break;
1181 }
1182 }
1183 if ( $allowed )
1184 {
1185 $newToCodeList[] = $toCode;
1186 }
1187 }
1188 $toCode = $newToCodeList;
1189 if ( count( $toCode ) > 0 )
1190 {
1191 if ( count( $toCode ) == 1 )
1192 $toCode = $toCode[0];
1193
1194 // If the mapping already exists we skip it
1195 if ( isset( $unicodeMap[$fromCode] ) )
1196 continue;
1197
1198 $unicodeMap = eZCodeMapper::mapExistingCodes( $unicodeMap, $fromCode, $toCode );
1199
1200 $unicodeMap[$fromCode] = $toCode;
1201 }
1202 }
1203 }
1204 }
1205 else if ( $type == self::TYPE_RANGE )
1206 {
1207 foreach ( $item as $rangeItem )
1208 {
1209 $start = $rangeItem[0];
1210 $stop = $rangeItem[1];
1211 if ( $start > $stop )
1212 {
1213 $tmp = $stop;
1214 $stop = $start;
1215 $start = $tmp;
1216 }
1217 $add = $rangeItem[2];
1218 $modulo = $rangeItem[3];
1219 // Sanity-check, to avoid infinite loops
1220 if ( $modulo == 0 )
1221 $modulo = 1;
1222 for ( $i = $start; $i <= $stop; $i += $modulo )
1223 {
1224 if ( count( $allowedRanges ) == 0 )
1225 {
1226 $allowed = true;
1227 }
1228 else
1229 {
1230 $allowed = false;
1231 foreach ( $allowedRanges as $allowedRange )
1232 {
1233 if ( $i >= $allowedRange[0] and
1234 $i <= $allowedRange[1] )
1235 {
1236 $allowed = true;
1237 break;
1238 }
1239 }
1240 if ( !$allowed )
1241 continue;
1242 }
1243
1244 $replace = $i + $add;
1245 $replace = eZCodeMapper::ordinalValues( $unicodeMap, $replace );
1246 if ( count( $allowedRanges ) == 0 )
1247 {
1248 if ( count( $replace ) == 0 )
1249 $replace = false;
1250 else if ( count( $replace ) == 1 )
1251 $replace = $replace[0];
1252 $unicodeMap = eZCodeMapper::mapExistingCodes( $unicodeMap, $i, $replace );
1253
1254 // If the mapping already exists we skip it
1255 if ( isset( $unicodeMap[$i] ) )
1256 continue;
1257
1258 $unicodeMap[$i] = $replace;
1259 }
1260 else
1261 {
1262 $newReplace = array();
1263 foreach ( $allowedRanges as $allowedRange )
1264 {
1265 foreach ( $replace as $replaceOrdinal )
1266 {
1267 if ( $replaceOrdinal >= $allowedRange[0] and
1268 $replaceOrdinal <= $allowedRange[1] )
1269 {
1270 $newReplace[] = $replaceOrdinal;
1271 }
1272 }
1273 }
1274 if ( count( $newReplace ) == 0 )
1275 $replace = false;
1276 else if ( count( $newReplace ) == 1 )
1277 $replace = $newReplace[0];
1278 else
1279 $replace = $newReplace;
1280
1281 // If the mapping already exists we skip it
1282 if ( isset( $unicodeMap[$i] ) )
1283 continue;
1284
1285 $unicodeMap = eZCodeMapper::mapExistingCodes( $unicodeMap, $i, $replace );
1286 $unicodeMap[$i] = $replace;
1287 }
1288 }
1289 }
1290 }
1291 else if ( $type == self::TYPE_REPLACE )
1292 {
1293 foreach ( $item as $rangeItem )
1294 {
1295 $start = $rangeItem[0];
1296 $stop = $rangeItem[1];
1297 if ( $start > $stop )
1298 {
1299 $tmp = $stop;
1300 $stop = $start;
1301 $start = $tmp;
1302 }
1303 $replace = $rangeItem[2];
1304 $replace = eZCodeMapper::ordinalValues( $unicodeMap, $replace );
1305 if ( count( $allowedRanges ) == 0 )
1306 {
1307 if ( count( $replace ) == 0 )
1308 $replace = false;
1309 else if ( count( $replace ) == 1 )
1310 $replace = $replace[0];
1311 for ( $i = $start; $i <= $stop; ++$i )
1312 {
1313 // If the mapping already exists we skip it
1314 if ( isset( $unicodeMap[$i] ) )
1315 continue;
1316
1317 $unicodeMap = eZCodeMapper::mapExistingCodes( $unicodeMap, $i, $replace );
1318 $unicodeMap[$i] = $replace;
1319 }
1320 }
1321 else
1322 {
1323 $newReplace = array();
1324 foreach ( $allowedRanges as $allowedRange )
1325 {
1326 foreach ( $replace as $replaceOrdinal )
1327 {
1328 if ( $replaceOrdinal >= $allowedRange[0] and
1329 $replaceOrdinal <= $allowedRange[1] )
1330 {
1331 $newReplace[] = $replaceOrdinal;
1332 }
1333 }
1334 }
1335 if ( count( $newReplace ) == 0 )
1336 $replace = false;
1337 else if ( count( $newReplace ) == 1 )
1338 $replace = $newReplace[0];
1339 else
1340 $replace = $newReplace;
1341 for ( $i = $start; $i <= $stop; ++$i )
1342 {
1343 $allowed = false;
1344 foreach ( $allowedRanges as $allowedRange )
1345 {
1346 if ( $i >= $allowedRange[0] and
1347 $i <= $allowedRange[1] )
1348 {
1349 $allowed = true;
1350 break;
1351 }
1352 }
1353 if ( $allowed )
1354 {
1355 // If the mapping already exists we skip it
1356 if ( isset( $unicodeMap[$i] ) )
1357 continue;
1358
1359 $unicodeMap = eZCodeMapper::mapExistingCodes( $unicodeMap, $i, $replace );
1360 $unicodeMap[$i] = $replace;
1361 }
1362 }
1363 }
1364 }
1365 }
1366 }
1367 return $unicodeMap;
1368 }
1369
1377 function generateMappingCode( $identifier )
1378 {
1379 if ( !is_array( $identifier ) )
1380 $identifier = array( $identifier );
1381 $table = $this->expandInheritance( $identifier );
1382
1383 // We allow all characters for now
1384 $allowedRanges = array();
1385 $simpleTable = $this->generateSimpleMappingTable( $table, $allowedRanges );
1386 ksort( $simpleTable );
1387 return $simpleTable;
1388 }
1389
1396 function generateCharsetMappingTable( $unicodeTable, $charset )
1397 {
1398 $codec = eZTextCodec::instance( 'unicode', $charset );
1399 if ( !$codec )
1400 {
1401 eZDebug::writeError( "Failed to create textcodec for charset '$charset'" );
1402 return false;
1403 }
1404
1405 $charsetTable = array();
1406 foreach ( $unicodeTable as $match => $replacement )
1407 {
1408 $matchLocal = $codec->convertString( array( $match ) );
1409 if ( is_array( $replacement ) )
1410 {
1411 $replacementLocal = $codec->convertString( $replacement );
1412 }
1413 else
1414 {
1415 $replacementLocal = $codec->convertString( array( $replacement ) );
1416 }
1417 $charsetTable[$matchLocal] = $replacementLocal;
1418 }
1419
1420 // Make sure longer string entries are placed before the shorter ones
1421 // This is very important when working with utf8 which have
1422 // variable length for characters
1423 krsort( $charsetTable );
1424 return $charsetTable;
1425 }
1426
1433 function decodeCommand( $name, $parameters )
1434 {
1435 $names = $this->ruleNames();
1436 $rules = array();
1437 switch ( $name )
1438 {
1439 // Special code handlers
1440 case 'url_cleanup_iri':
1441 case 'url_cleanup':
1442 case 'url_cleanup_compat':
1443 case 'identifier_cleanup':
1444 {
1445 } break;
1446
1447 case 'normalize':
1448 case 'search_normalize':
1449 case 'decompose':
1450 case 'diacritical':
1451 case 'lowercase':
1452 case 'uppercase':
1453 case 'search_cleanup':
1454 {
1455 if ( count( $parameters ) == 0 )
1456 {
1457 // Include all normalize rules
1458 foreach ( $names as $rule )
1459 {
1460 if ( preg_match( '#_'. $name . '$#', $rule ) )
1461 $rules[] = $rule;
1462 }
1463 }
1464 else
1465 {
1466 foreach ( $parameters as $parameter )
1467 {
1468 $rule = $parameter . '_' . $name;
1469 if ( in_array( $rule, $names ) )
1470 $rules[] = $rule;
1471 }
1472 }
1473 } break;
1474
1475 case 'transform':
1476 case 'transliterate':
1477 {
1478 $dividers = array( 'transform' => '_to_',
1479 'transliterate' => '_transliterate_' );
1480 $divider = $dividers[$name];
1481 if ( count( $parameters ) == 0 )
1482 {
1483 // Include all transformation rules
1484 foreach ( $names as $rule )
1485 {
1486 if ( preg_match( '#^[a-zA-Z][a-zA-Z0-9-]+'. $divider . '[a-zA-Z][a-zA-Z0-9-]+$#', $rule ) )
1487 $rules[] = $rule;
1488 }
1489 }
1490 else if ( count( $parameters ) == 2 )
1491 {
1492 $rule = $parameters[0] . $divider . $parameters[1];
1493 if ( in_array( $rule, $names ) )
1494 $rules[] = $rule;
1495 }
1496 } break;
1497
1498 default:
1499 {
1500 $ini = eZINI::instance( 'transform.ini' );
1501 $commands = $ini->variable( 'Extensions', 'Commands' );
1502 if ( isset( $commands[$name] ) )
1503 {
1504 break;
1505 }
1506 eZDebug::writeError( "Unknown command '$name'", __METHOD__ );
1507 } break;
1508 }
1509 return $rules;
1510 }
1511
1518 function generateCommandCode( $command, $charsetName )
1519 {
1520 if ( $command['command'] == 'url_cleanup_iri' )
1521 {
1522 $charsetNameTxt = var_export( $charsetName, true );
1523 $code = "\$text = eZCharTransform::commandUrlCleanupIRI( \$text, $charsetNameTxt );\n";
1524 return $code;
1525 }
1526 else if ( $command['command'] == 'url_cleanup' )
1527 {
1528 $charsetNameTxt = var_export( $charsetName, true );
1529 $code = "\$text = eZCharTransform::commandUrlCleanup( \$text, $charsetNameTxt );\n";
1530 return $code;
1531 }
1532 else if ( $command['command'] == 'url_cleanup_compat' )
1533 {
1534 $charsetNameTxt = var_export( $charsetName, true );
1535 $code = "\$text = eZCharTransform::commandUrlCleanupCompat( \$text, $charsetNameTxt );\n";
1536 return $code;
1537 }
1538 else if ( $command['command'] == 'identifier_cleanup' )
1539 {
1540 $code = ( "\$text = strtolower( \$text );\n" .
1541 "\$text = preg_replace( array( \"#[^a-z0-9_ ]#\",\n" .
1542 " \"/ /\",\n" .
1543 " \"/__+/\",\n" .
1544 " \"/^_|_$/\" ),\n" .
1545 " array( \" \",\n" .
1546 " \"_\",\n" .
1547 " \"_\",\n" .
1548 " \"\" ),\n" .
1549 " \$text );\n" );
1550 return $code;
1551 }
1552 else if ( $command['command'] == 'search_cleanup' )
1553 {
1554 $code = '';
1555 $nonCJKCharsets = $this->nonCJKCharsets();
1556 if ( !in_array( $charsetName, $nonCJKCharsets ) )
1557 {
1558 $code .= ( '// add N-Gram(N=2) chinese / japanese / korean multibyte characters' . "\n" .
1559 '$codec = eZTextCodec::instance( false, \'unicode\' );' . "\n" .
1560 "\n" .
1561 '$unicodeValueArray = $codec->convertString( $text );' . "\n" .
1562 "\n" .
1563 '$normalizedTextArray = array();' . "\n" .
1564 '$bFlag = false;' . "\n" .
1565 'foreach ( array_keys( $unicodeValueArray ) as $valueKey )' . "\n" .
1566 '{' . "\n" .
1567 ' // Check for word characters that should be broken up for search' . "\n" .
1568 ' if ( ( $unicodeValueArray[$valueKey] >= 12289 and' . "\n" .
1569 ' $unicodeValueArray[$valueKey] <= 12542 ) or' . "\n" .
1570 ' ( $unicodeValueArray[$valueKey] >= 13312 and' . "\n" .
1571 ' $unicodeValueArray[$valueKey] <= 40863 ) or' . "\n" .
1572 ' ( $unicodeValueArray[$valueKey] >= 44032 and' . "\n" .
1573 ' $unicodeValueArray[$valueKey] <= 55203 ) )' . "\n" .
1574 ' {' . "\n" .
1575 ' if ( $bFlag )' . "\n" .
1576 ' {' . "\n" .
1577 ' $normalizedTextArray[] = $unicodeValueArray[$valueKey];' . "\n" .
1578 ' }' . "\n" .
1579 ' $normalizedTextArray[] = 32; // A space' . "\n" .
1580 ' $normalizedTextArray[] = $unicodeValueArray[$valueKey];' . "\n" .
1581 ' $bFlag = true;' . "\n" .
1582 ' }' . "\n" .
1583 ' else' . "\n" .
1584 ' {' . "\n" .
1585 ' if ( $bFlag )' . "\n" .
1586 ' {' . "\n" .
1587 ' $normalizedTextArray[] = 32; // A space' . "\n" .
1588 ' }' . "\n" .
1589 ' $normalizedTextArray[] = $unicodeValueArray[$valueKey];' . "\n" .
1590 ' $bFlag = false;' . "\n" .
1591 ' }' . "\n" .
1592 '}' . "\n" .
1593 'if ( $bFlag )' . "\n" .
1594 '{' . "\n" .
1595 ' $normalizedTextArray[count($normalizedTextArray)-1]=32;' . "\n" .
1596 '}' . "\n" .
1597 '$revCodec = eZTextCodec::instance( \'unicode\', false ); // false means use internal charset' . "\n" .
1598 '$text = $revCodec->convertString( $normalizedTextArray );' . "\n" );
1599 }
1600 $code .= ( '$text = preg_replace( array( "#(\.){2,}#",' . "\n" .
1601 ' "#^\.#",' . "\n" .
1602 ' "#\s\.#",' . "\n" .
1603 ' "#\.\s#",' . "\n" .
1604 ' "#\.$#",' . "\n" .
1605 ' "#([^0-9])%#" ),' . "\n" .
1606 ' array( " ",' . "\n" .
1607 ' " ",' . "\n" .
1608 ' " ",' . "\n" .
1609 ' " ",' . "\n" .
1610 ' " ",' . "\n" .
1611 ' " " ),' . "\n" .
1612 ' $text );' . "\n" .
1613 '$ini = eZINI::instance();' . "\n" .
1614 'if ( $ini->variable( \'SearchSettings\', \'EnableWildcard\' ) != \'true\' )' . "\n" .
1615 '{' . "\n" .
1616 ' $text = str_replace( "*", " ", $text );' . "\n" .
1617 '}' . "\n" .
1618 '$charset = eZTextCodec::internalCharset();' . "\n" .
1619 '$hasUTF8 = ( $charset == "utf-8" );' . "\n" .
1620 "\n" .
1621 'if ( $hasUTF8 )' . "\n" .
1622 '{' . "\n" .
1623 ' $text = preg_replace( "#(\s+)#u", " ", $text );' . "\n" .
1624 '}' . "\n" .
1625 'else' . "\n" .
1626 '{' . "\n" .
1627 ' $text = preg_replace( "#(\s+)#", " ", $text );' . "\n" .
1628 '}' );
1629
1630 return $code;
1631 }
1632 else
1633 {
1634 $ini = eZINI::instance( 'transform.ini' );
1635 $commands = $ini->variable( 'Extensions', 'Commands' );
1636 if ( isset( $commands[$command['command']] ) )
1637 {
1638 list( $path, $className ) = explode( ':', $commands[$command['command']], 2 );
1639 if ( file_exists( $path ) )
1640 {
1641 $charsetNameTxt = var_export( $charsetName, true );
1642 $commandTxt = var_export( $command['command'], true );
1643 $pathTxt = var_export( $path, true );
1644 $code = "include_once( $pathTxt );\n\$text = $className::executeCommand( \$text, $commandTxt, $charsetNameTxt );\n";
1645 return $code;
1646 }
1647 else
1648 {
1649 eZDebug::writeError( "Could not locate include file '$path' for transformation '" . $command['command'] . "'" );
1650 }
1651 }
1652 }
1653 return false;
1654 }
1655
1662 function executeCommandCode( &$text, $command, $charsetName )
1663 {
1664 if ( $command['command'] == 'url_cleanup_iri' )
1665 {
1666 $text = eZCharTransform::commandUrlCleanupIRI( $text, $charsetName );
1667 return true;
1668 }
1669 else if ( $command['command'] == 'url_cleanup' )
1670 {
1671 $text = eZCharTransform::commandUrlCleanup( $text, $charsetName );
1672 return true;
1673 }
1674 else if ( $command['command'] == 'url_cleanup_compat' )
1675 {
1676 $text = eZCharTransform::commandUrlCleanupCompat( $text, $charsetName );
1677 return true;
1678 }
1679 else if ( $command['command'] == 'identifier_cleanup' )
1680 {
1681 $text = strtolower( $text );
1682 $text = preg_replace( array( "#[^a-z0-9_ ]#",
1683 "/ /",
1684 "/__+/",
1685 "/^_|_$/" ),
1686 array( " ",
1687 "_",
1688 "_",
1689 "" ),
1690 $text );
1691 return true;
1692 }
1693 else if ( $command['command'] == 'search_cleanup' )
1694 {
1695 $nonCJKCharsets = $this->nonCJKCharsets();
1696 if ( !in_array( $charsetName, $nonCJKCharsets ) )
1697 {
1698 // 4 Add spaces after chinese / japanese / korean multibyte characters
1699 $codec = eZTextCodec::instance( false, 'unicode' );
1700
1701 $unicodeValueArray = $codec->convertString( $text );
1702
1703 $normalizedTextArray = array();
1704 $bFlag = false;
1705 foreach ( array_keys( $unicodeValueArray ) as $valueKey )
1706 {
1707 // Check for word characters that should be broken up for search
1708 if ( ( $unicodeValueArray[$valueKey] >= 12289 and
1709 $unicodeValueArray[$valueKey] <= 12542 ) or
1710 ( $unicodeValueArray[$valueKey] >= 13312 and
1711 $unicodeValueArray[$valueKey] <= 40863 ) or
1712 ( $unicodeValueArray[$valueKey] >= 44032 and
1713 $unicodeValueArray[$valueKey] <= 55203 ) )
1714 {
1715 if ( $bFlag )
1716 {
1717 $normalizedTextArray[] = $unicodeValueArray[$valueKey];
1718 }
1719 $normalizedTextArray[] = 32; // A space
1720 $normalizedTextArray[] = $unicodeValueArray[$valueKey];
1721 $bFlag = true;
1722 }
1723 else
1724 {
1725 if ( $bFlag )
1726 {
1727 $normalizedTextArray[] = 32; // A space
1728 }
1729 $normalizedTextArray[] = $unicodeValueArray[$valueKey];
1730 $bFlag = false;
1731 }
1732 }
1733
1734 if ( $bFlag )
1735 {
1736 $normalizedTextArray[ count( $normalizedTextArray ) - 1 ] = 32;
1737 }
1738
1739 $revCodec = eZTextCodec::instance( 'unicode', false ); // false means use internal charset
1740 $text = $revCodec->convertString( $normalizedTextArray );
1741 }
1742
1743 // Make sure dots inside words/numbers are kept, the rest is turned into space
1744 $text = preg_replace( array( "#(\.){2,}#",
1745 "#^\.#",
1746 "#\s\.#",
1747 "#\.\s#",
1748 "#\.$#",
1749 "#([^0-9])%#" ), // Keep only % after a number
1750 array( " ",
1751 " ",
1752 " ",
1753 " ",
1754 " ",
1755 "$1 " ),
1756 $text );
1757 $ini = eZINI::instance();
1758 if ( $ini->variable( 'SearchSettings', 'EnableWildcard' ) != 'true' )
1759 {
1760 $text = str_replace( "*", " ", $text );
1761 }
1762 $charset = eZTextCodec::internalCharset();
1763 $hasUTF8 = ( $charset == "utf-8" );
1764
1765 if ( $hasUTF8 )
1766 {
1767 $text = preg_replace( "#(\s+)#u", " ", $text );
1768 }
1769 else
1770 {
1771 $text = preg_replace( "#(\s+)#", " ", $text );
1772 }
1773
1774 return true;
1775 }
1776 else
1777 {
1778 $ini = eZINI::instance( 'transform.ini' );
1779 $commands = $ini->variable( 'Extensions', 'Commands' );
1780 if ( isset( $commands[$command['command']] ) )
1781 {
1782 list( $path, $className ) = explode( ':', $commands[$command['command']], 2 );
1783 if ( file_exists( $path ) )
1784 {
1785 include_once( $path );
1786 $text = call_user_func_array( array( $className, 'executeCommand' ),
1787 array( $text, $command['command'], $charsetName ) );
1788 return true;
1789 }
1790 else
1791 {
1792 eZDebug::writeError( "Could not locate include file '$path' for transformation '" . $command['command'] . "'" );
1793 }
1794 }
1795 }
1796 return false;
1797 }
1798
1802 function nonCJKCharsets()
1803 {
1804 return array( 'adobe-standard-encoding',
1805 'cp437', 'cp737', 'cp775', 'cp850', 'cp852', 'cp855', 'cp857',
1806 'cp860', 'cp861', 'cp862', 'cp863', 'cp864', 'cp865', 'cp866',
1807 'cp869', 'cp874',
1808 'dec-mcs', 'hp-roman8',
1809 'iso-8859-1', 'iso-8859-2', 'iso-8859-3', 'iso-8859-4', 'iso-8859-5',
1810 'iso-8859-6', 'iso-8859-7', 'iso-8859-8', 'iso-8859-9', 'iso-8859-10',
1811 'iso-8859-11', 'iso-8859-13', 'iso-8859-14', 'iso-8859-15',
1812 'koi8-r', 'koi8-u', 'macintosh', 'next', 'us-ascii',
1813 'windows-1250', 'windows-1251', 'windows-1252', 'windows-1253',
1814 'windows-1254', 'windows-1255', 'windows-1256', 'windows-1257',
1815 'windows-1258' );
1816 }
1817
1819 public $TransformationTables;
1820 public $TransformationFiles;
1821 public $ISOUnicodeCodec;
1822 }
1823
1824 ?>
eZCLI\instance
static instance()
Definition: ezcli.php:717
eZCharTransform\commandUrlCleanupCompat
static commandUrlCleanupCompat( $text, $charsetName)
Definition: ezchartransform.php:375
eZCharTransform\commandUrlCleanup
static commandUrlCleanup( $text, $charsetName)
Definition: ezchartransform.php:387
eZCharTransform\commandUrlCleanupIRI
static commandUrlCleanupIRI( $text, $charsetName)
Definition: ezchartransform.php:403
eZCharsetInfo\realCharsetCode
static realCharsetCode( $charsetCode)
Definition: ezcharsetinfo.php:186
eZCodeMapper
Handles mapping of character codes.
Definition: ezcodemapper.php:19
eZCodeMapper\extractUnicodeValues
extractUnicodeValues( $data)
Definition: ezcodemapper.php:950
eZCodeMapper\parseTransformationFile
parseTransformationFile( $filename, $name)
Definition: ezcodemapper.php:176
eZCodeMapper\TYPE_DIRECT
const TYPE_DIRECT
Definition: ezcodemapper.php:20
eZCodeMapper\appendReplaceMapping
appendReplaceMapping(&$block, $identifier, $sourceValue, $sourceEndValue, $destinationValues)
Definition: ezcodemapper.php:867
eZCodeMapper\TYPE_RANGE
const TYPE_RANGE
Definition: ezcodemapper.php:21
eZCodeMapper\generateCommandCode
generateCommandCode( $command, $charsetName)
Definition: ezcodemapper.php:1518
eZCodeMapper\ruleNames
ruleNames()
Definition: ezcodemapper.php:43
eZCodeMapper\mapExistingCodes
mapExistingCodes( $unicodeMap, $fromCode, $toCode)
Definition: ezcodemapper.php:1075
eZCodeMapper\generateSimpleMappingTable
generateSimpleMappingTable( $table, $allowedRanges)
Definition: ezcodemapper.php:1112
eZCodeMapper\$TransformationFiles
$TransformationFiles
Definition: ezcodemapper.php:1820
eZCodeMapper\executeCommandCode
executeCommandCode(&$text, $command, $charsetName)
Definition: ezcodemapper.php:1662
eZCodeMapper\$TransformationTables
$TransformationTables
Definition: ezcodemapper.php:1819
eZCodeMapper\ordinalValues
ordinalValues( $table, $list)
Definition: ezcodemapper.php:1017
eZCodeMapper\error
error( $text, $position=false)
Definition: ezcodemapper.php:51
eZCodeMapper\mapOrdinals
mapOrdinals( $table, $ordinals)
Definition: ezcodemapper.php:1048
eZCodeMapper\decodeCommand
decodeCommand( $name, $parameters)
Definition: ezcodemapper.php:1433
eZCodeMapper\__construct
__construct()
Definition: ezcodemapper.php:24
eZCodeMapper\nonCJKCharsets
nonCJKCharsets()
Definition: ezcodemapper.php:1802
eZCodeMapper\warning
warning( $text, $position=false)
Definition: ezcodemapper.php:75
eZCodeMapper\generateCharsetMappingTable
generateCharsetMappingTable( $unicodeTable, $charset)
Definition: ezcodemapper.php:1396
eZCodeMapper\mappingTable
mappingTable( $identifier)
Definition: ezcodemapper.php:33
eZCodeMapper\extractUnicodeValue
extractUnicodeValue( $data)
Definition: ezcodemapper.php:919
eZCodeMapper\generateMappingCode
generateMappingCode( $identifier)
Definition: ezcodemapper.php:1377
eZCodeMapper\appendDirectMapping
appendDirectMapping(&$block, $identifier, $sourceValue, $destinationValues)
Definition: ezcodemapper.php:838
eZCodeMapper\expandInheritance
expandInheritance( $table)
Definition: ezcodemapper.php:982
eZCodeMapper\loadTransformationFiles
loadTransformationFiles( $currentCharset, $transformationGroup)
Definition: ezcodemapper.php:112
eZCodeMapper\isTranformationLoaded
isTranformationLoaded( $name)
Definition: ezcodemapper.php:99
eZCodeMapper\TYPE_REPLACE
const TYPE_REPLACE
Definition: ezcodemapper.php:22
eZCodeMapper\appendTransposeMapping
appendTransposeMapping(&$block, $identifier, $sourceValue, $sourceEndValue, $transposeValue, $addValue, $moduloValue)
Definition: ezcodemapper.php:897
eZCodeMapper\$ISOUnicodeCodec
$ISOUnicodeCodec
Definition: ezcodemapper.php:1821
eZDebug\writeError
static writeError( $string, $label="", $backgroundClass="")
Definition: ezdebug.php:545
eZDebug\writeWarning
static writeWarning( $string, $label="", $backgroundClass="")
Definition: ezdebug.php:502
eZExtension\expandedPathList
static expandedPathList( $extensionList, $subdirectory=false)
Definition: ezextension.php:334
eZTextCodec\internalCharset
static internalCharset()
Definition: eztextcodec.php:546
eZTextCodec\instance
static instance( $inputCharsetCode, $outputCharsetCode=false, $alwaysReturn=true)
Definition: eztextcodec.php:446
Copyright © 1998 – 2026 7x. All rights reserved. Licensed under the GNU GPLv2+.