run:R W Run
12.67 KB
2026-03-11 16:18:52
R W Run
6.22 KB
2026-03-11 16:18:52
R W Run
1.77 KB
2026-03-11 16:18:52
R W Run
6.13 KB
2026-03-11 16:18:52
R W Run
3.72 KB
2026-03-11 16:18:52
R W Run
error_log
📄class-wp-translation-file-mo.php
1<?php
2/**
3 * I18N: WP_Translation_File_MO class.
4 *
5 * @package WordPress
6 * @subpackage I18N
7 * @since 6.5.0
8 */
9
10/**
11 * Class WP_Translation_File_MO.
12 *
13 * @since 6.5.0
14 */
15class WP_Translation_File_MO extends WP_Translation_File {
16 /**
17 * Endian value.
18 *
19 * V for little endian, N for big endian, or false.
20 *
21 * Used for unpack().
22 *
23 * @since 6.5.0
24 * @var false|'V'|'N'
25 */
26 protected $uint32 = false;
27
28 /**
29 * The magic number of the GNU message catalog format.
30 *
31 * @since 6.5.0
32 * @var int
33 */
34 const MAGIC_MARKER = 0x950412de;
35
36 /**
37 * Detects endian and validates file.
38 *
39 * @since 6.5.0
40 *
41 * @param string $header File contents.
42 * @return false|'V'|'N' V for little endian, N for big endian, or false on failure.
43 */
44 protected function detect_endian_and_validate_file( string $header ) {
45 $big = unpack( 'N', $header );
46
47 if ( false === $big ) {
48 return false;
49 }
50
51 $big = reset( $big );
52
53 if ( false === $big ) {
54 return false;
55 }
56
57 $little = unpack( 'V', $header );
58
59 if ( false === $little ) {
60 return false;
61 }
62
63 $little = reset( $little );
64
65 if ( false === $little ) {
66 return false;
67 }
68
69 // Force cast to an integer as it can be a float on x86 systems. See https://core.trac.wordpress.org/ticket/60678.
70 if ( (int) self::MAGIC_MARKER === $big ) {
71 return 'N';
72 }
73
74 // Force cast to an integer as it can be a float on x86 systems. See https://core.trac.wordpress.org/ticket/60678.
75 if ( (int) self::MAGIC_MARKER === $little ) {
76 return 'V';
77 }
78
79 $this->error = 'Magic marker does not exist';
80 return false;
81 }
82
83 /**
84 * Parses the file.
85 *
86 * @since 6.5.0
87 *
88 * @return bool True on success, false otherwise.
89 */
90 protected function parse_file(): bool {
91 $this->parsed = true;
92
93 $file_contents = file_get_contents( $this->file ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
94
95 if ( false === $file_contents ) {
96 return false;
97 }
98
99 $file_length = strlen( $file_contents );
100
101 if ( $file_length < 24 ) {
102 $this->error = 'Invalid data';
103 return false;
104 }
105
106 $this->uint32 = $this->detect_endian_and_validate_file( substr( $file_contents, 0, 4 ) );
107
108 if ( false === $this->uint32 ) {
109 return false;
110 }
111
112 $offsets = substr( $file_contents, 4, 24 );
113
114 if ( false === $offsets ) {
115 return false;
116 }
117
118 $offsets = unpack( "{$this->uint32}rev/{$this->uint32}total/{$this->uint32}originals_addr/{$this->uint32}translations_addr/{$this->uint32}hash_length/{$this->uint32}hash_addr", $offsets );
119
120 if ( false === $offsets ) {
121 return false;
122 }
123
124 $offsets['originals_length'] = $offsets['translations_addr'] - $offsets['originals_addr'];
125 $offsets['translations_length'] = $offsets['hash_addr'] - $offsets['translations_addr'];
126
127 if ( $offsets['rev'] > 0 ) {
128 $this->error = 'Unsupported revision';
129 return false;
130 }
131
132 if ( $offsets['translations_addr'] > $file_length || $offsets['originals_addr'] > $file_length ) {
133 $this->error = 'Invalid data';
134 return false;
135 }
136
137 // Load the Originals.
138 $original_data = str_split( substr( $file_contents, $offsets['originals_addr'], $offsets['originals_length'] ), 8 );
139 $translations_data = str_split( substr( $file_contents, $offsets['translations_addr'], $offsets['translations_length'] ), 8 );
140
141 foreach ( array_keys( $original_data ) as $i ) {
142 $o = unpack( "{$this->uint32}length/{$this->uint32}pos", $original_data[ $i ] );
143 $t = unpack( "{$this->uint32}length/{$this->uint32}pos", $translations_data[ $i ] );
144
145 if ( false === $o || false === $t ) {
146 continue;
147 }
148
149 $original = substr( $file_contents, $o['pos'], $o['length'] );
150 $translation = substr( $file_contents, $t['pos'], $t['length'] );
151 // GlotPress bug.
152 $translation = rtrim( $translation, "\0" );
153
154 // Metadata about the MO file is stored in the first translation entry.
155 if ( '' === $original ) {
156 foreach ( explode( "\n", $translation ) as $meta_line ) {
157 if ( '' === $meta_line || ! str_contains( $meta_line, ':' ) ) {
158 continue;
159 }
160
161 list( $name, $value ) = array_map( 'trim', explode( ':', $meta_line, 2 ) );
162
163 $this->headers[ strtolower( $name ) ] = $value;
164 }
165 } else {
166 /*
167 * In MO files, the key normally contains both singular and plural versions.
168 * However, this just adds the singular string for lookup,
169 * which caters for cases where both __( 'Product' ) and _n( 'Product', 'Products' )
170 * are used and the translation is expected to be the same for both.
171 */
172 $parts = explode( "\0", (string) $original );
173
174 $this->entries[ $parts[0] ] = $translation;
175 }
176 }
177
178 return true;
179 }
180
181 /**
182 * Exports translation contents as a string.
183 *
184 * @since 6.5.0
185 *
186 * @return string Translation file contents.
187 */
188 public function export(): string {
189 // Prefix the headers as the first key.
190 $headers_string = '';
191 foreach ( $this->headers as $header => $value ) {
192 $headers_string .= "{$header}: $value\n";
193 }
194 $entries = array_merge( array( '' => $headers_string ), $this->entries );
195 $entry_count = count( $entries );
196
197 if ( false === $this->uint32 ) {
198 $this->uint32 = 'V';
199 }
200
201 $bytes_for_entries = $entry_count * 4 * 2;
202 // Pair of 32bit ints per entry.
203 $originals_addr = 28; /* header */
204 $translations_addr = $originals_addr + $bytes_for_entries;
205 $hash_addr = $translations_addr + $bytes_for_entries;
206 $entry_offsets = $hash_addr;
207
208 $file_header = pack(
209 $this->uint32 . '*',
210 // Force cast to an integer as it can be a float on x86 systems. See https://core.trac.wordpress.org/ticket/60678.
211 (int) self::MAGIC_MARKER,
212 0, /* rev */
213 $entry_count,
214 $originals_addr,
215 $translations_addr,
216 0, /* hash_length */
217 $hash_addr
218 );
219
220 $o_entries = '';
221 $t_entries = '';
222 $o_addr = '';
223 $t_addr = '';
224
225 foreach ( array_keys( $entries ) as $original ) {
226 $o_addr .= pack( $this->uint32 . '*', strlen( $original ), $entry_offsets );
227 $entry_offsets += strlen( $original ) + 1;
228 $o_entries .= $original . "\0";
229 }
230
231 foreach ( $entries as $translations ) {
232 $t_addr .= pack( $this->uint32 . '*', strlen( $translations ), $entry_offsets );
233 $entry_offsets += strlen( $translations ) + 1;
234 $t_entries .= $translations . "\0";
235 }
236
237 return $file_header . $o_addr . $t_addr . $o_entries . $t_entries;
238 }
239}
240
Ui Ux Design – Teachers Night Out

Get in Touch

© 2024 Teachers Night Out. All Rights Reserved.