00001 <?php 00016 class TranslateYaml { 00021 public static function parseGroupFile( $filename ) { 00022 $data = file_get_contents( $filename ); 00023 $documents = preg_split( "/^---$/m", $data, -1, PREG_SPLIT_NO_EMPTY ); 00024 $groups = array(); 00025 $template = false; 00026 foreach ( $documents as $document ) { 00027 $document = self::loadString( $document ); 00028 00029 if ( isset( $document['TEMPLATE'] ) ) { 00030 $template = $document['TEMPLATE']; 00031 } else { 00032 if ( !isset( $document['BASIC']['id'] ) ) { 00033 $error = "No path ./BASIC/id (group id not defined) "; 00034 $error .= "in YAML document located in $filename"; 00035 trigger_error( $error ); 00036 continue; 00037 } 00038 $groups[$document['BASIC']['id']] = $document; 00039 } 00040 } 00041 00042 foreach ( $groups as $i => $group ) { 00043 $groups[$i] = self::mergeTemplate( $template, $group ); 00044 } 00045 00046 return $groups; 00047 } 00048 00055 public static function mergeTemplate( $base, $specific ) { 00056 foreach ( $specific as $key => $value ) { 00057 if ( is_array( $value ) && isset( $base[$key] ) && is_array( $base[$key] ) ) { 00058 $base[$key] = self::mergeTemplate( $base[$key], $value ); 00059 } else { 00060 $base[$key] = $value; 00061 } 00062 } 00063 00064 return $base; 00065 } 00066 00072 public static function loadString( $text ) { 00073 global $wgTranslateYamlLibrary; 00074 00075 switch ( $wgTranslateYamlLibrary ) { 00076 case 'spyc': 00077 require_once __DIR__ . '/../libs/spyc/spyc.php'; 00078 $yaml = spyc_load( $text ); 00079 00080 return self::fixSpycSpaces( $yaml ); 00081 case 'syck': 00082 $yaml = self::syckLoad( $text ); 00083 00084 return self::fixSyckBooleans( $yaml ); 00085 case 'syck-pecl': 00086 $text = preg_replace( '~^(\s*)no(\s*:\s*[a-zA-Z-_]+\s*)$~m', '\1"no"\2', $text ); 00087 00088 return syck_load( $text ); 00089 default: 00090 throw new MWException( "Unknown Yaml library" ); 00091 } 00092 } 00093 00098 public static function fixSyckBooleans( &$yaml ) { 00099 foreach ( $yaml as &$value ) { 00100 if ( is_array( $value ) ) { 00101 self::fixSyckBooleans( $value ); 00102 } elseif ( $value === 'yes' ) { 00103 $value = true; 00104 } 00105 } 00106 00107 return $yaml; 00108 } 00109 00114 public static function fixSpycSpaces( &$yaml ) { 00115 foreach ( $yaml as $key => &$value ) { 00116 if ( is_array( $value ) ) { 00117 self::fixSpycSpaces( $value ); 00118 } elseif ( is_string( $value ) && $key === 'header' ) { 00119 $value = preg_replace( '~^\*~m', ' *', $value ) . "\n"; 00120 } 00121 } 00122 00123 return $yaml; 00124 } 00125 00126 public static function load( $file ) { 00127 $text = file_get_contents( $file ); 00128 00129 return self::loadString( $text ); 00130 } 00131 00132 public static function dump( $text ) { 00133 global $wgTranslateYamlLibrary; 00134 00135 switch ( $wgTranslateYamlLibrary ) { 00136 case 'spyc': 00137 require_once __DIR__ . '/../libs/spyc/spyc.php'; 00138 00139 return Spyc::YAMLDump( $text ); 00140 case 'syck-pecl': 00141 // Just horrible output 00142 // return syck_dump( $text ); 00143 case 'syck': 00144 return self::syckDump( $text ); 00145 default: 00146 throw new MWException( "Unknown Yaml library" ); 00147 } 00148 } 00149 00150 protected static function syckLoad( $data ) { 00151 # Make temporary file 00152 $td = wfTempDir(); 00153 $tf = tempnam( $td, 'yaml-load-' ); 00154 00155 # Write to file 00156 file_put_contents( $tf, $data ); 00157 00158 $cmd = "perl -MYAML::Syck=LoadFile -MPHP::Serialization=serialize -wle '" . 00159 'my $tf = q[' . $tf . '];' . 00160 'my $yaml = LoadFile($tf);' . 00161 'open my $fh, ">", "$tf.serialized" or die qq[Can not open "$tf.serialized"];' . 00162 'print $fh serialize($yaml);' . 00163 'close($fh);' . 00164 "' 2>&1"; 00165 00166 $out = wfShellExec( $cmd, $ret ); 00167 00168 if ( $ret != 0 ) { 00169 throw new MWException( "The command '$cmd' died in execution with exit code '$ret': $out" ); 00170 } 00171 00172 $serialized = file_get_contents( "$tf.serialized" ); 00173 $php_data = unserialize( $serialized ); 00174 00175 unlink( $tf ); 00176 unlink( "$tf.serialized" ); 00177 00178 return $php_data; 00179 } 00180 00181 protected static function syckDump( $data ) { 00182 # Make temporary file 00183 $td = wfTempDir(); 00184 $tf = tempnam( $td, 'yaml-load-' ); 00185 00186 # Write to file 00187 $sdata = serialize( $data ); 00188 file_put_contents( $tf, $sdata ); 00189 00190 $cmd = "perl -MYAML::Syck=DumpFile -MPHP::Serialization=unserialize -MFile::Slurp=slurp -we '" . 00191 '$YAML::Syck::Headless = 1;' . 00192 '$YAML::Syck::SortKeys = 1;' . 00193 'my $tf = q[' . $tf . '];' . 00194 'my $serialized = slurp($tf);' . 00195 'my $unserialized = unserialize($serialized);' . 00196 'my $unserialized_utf8 = deutf8($unserialized);' . 00197 'DumpFile(qq[$tf.yaml], $unserialized_utf8);' . 00198 'sub deutf8 {' . 00199 'if(ref($_[0]) eq "HASH") {' . 00200 'return { map { deutf8($_) } %{$_[0]} };' . 00201 '} elsif(ref($_[0]) eq "ARRAY") {' . 00202 'return [ map { deutf8($_) } @{$_[0]} ];' . 00203 '} else {' . 00204 'my $s = $_[0];' . 00205 'utf8::decode($s);' . 00206 'return $s;' . 00207 '}' . 00208 '}' . 00209 "' 2>&1"; 00210 $out = wfShellExec( $cmd, $ret ); 00211 if ( $ret != 0 ) { 00212 throw new MWException( "The command '$cmd' died in execution with exit code '$ret': $out" ); 00213 } 00214 00215 $yaml = file_get_contents( "$tf.yaml" ); 00216 00217 unlink( $tf ); 00218 unlink( "$tf.yaml" ); 00219 00220 return $yaml; 00221 } 00222 }