Completed
Push — master ( a7cd2a...eabd6c )
by Stephen
38:42
created

PO   D

Complexity

Total Complexity 98

Size/Duplication

Total Lines 424
Duplicated Lines 0.47 %

Coupling/Cohesion

Components 1
Dependencies 2
Metric Value
wmc 98
lcom 1
cbo 2
dl 2
loc 424
rs 4.8717

16 Methods

Rating   Name   Duplication   Size   Complexity  
A export_headers() 0 12 3
A export_entries() 0 4 1
A export() 0 9 2
A export_to_file() 0 8 3
A set_comment_before_headers() 0 3 1
B poify() 0 23 4
B unpoify() 0 27 6
A prepend_each_line() 0 10 3
A comment_block() 0 4 1
D export_entry() 2 23 12
C match_begin_and_end_newlines() 0 28 8
C import_from_file() 0 22 8
D read_entry() 0 104 34
B read_line() 0 17 5
A add_comment_to_entry() 0 13 4
A trim_quotes() 0 5 3

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like PO often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use PO, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Class for working with PO files
4
 *
5
 * @version $Id: po.php 1158 2015-11-20 04:31:23Z dd32 $
6
 * @package pomo
7
 * @subpackage po
8
 */
9
10
require_once dirname(__FILE__) . '/translations.php';
11
12
if ( ! defined( 'PO_MAX_LINE_LEN' ) ) {
13
	define('PO_MAX_LINE_LEN', 79);
14
}
15
16
ini_set('auto_detect_line_endings', 1);
17
18
/**
19
 * Routines for working with PO files
20
 */
21
if ( ! class_exists( 'PO', false ) ):
22
class PO extends Gettext_Translations {
23
24
	var $comments_before_headers = '';
25
26
	/**
27
	 * Exports headers to a PO entry
28
	 *
29
	 * @return string msgid/msgstr PO entry for this PO file headers, doesn't contain newline at the end
30
	 */
31
	function export_headers() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
32
		$header_string = '';
33
		foreach($this->headers as $header => $value) {
0 ignored issues
show
Bug introduced by
The property headers cannot be accessed from this context as it is declared private in class Translations.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
34
			$header_string.= "$header: $value\n";
35
		}
36
		$poified = PO::poify($header_string);
37
		if ($this->comments_before_headers)
38
			$before_headers = $this->prepend_each_line(rtrim($this->comments_before_headers)."\n", '# ');
39
		else
40
			$before_headers = '';
41
		return rtrim("{$before_headers}msgid \"\"\nmsgstr $poified");
42
	}
43
44
	/**
45
	 * Exports all entries to PO format
46
	 *
47
	 * @return string sequence of mgsgid/msgstr PO strings, doesn't containt newline at the end
48
	 */
49
	function export_entries() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
50
		//TODO sorting
51
		return implode("\n\n", array_map(array('PO', 'export_entry'), $this->entries));
0 ignored issues
show
Bug introduced by
The property entries cannot be accessed from this context as it is declared private in class Translations.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
52
	}
53
54
	/**
55
	 * Exports the whole PO file as a string
56
	 *
57
	 * @param bool $include_headers whether to include the headers in the export
58
	 * @return string ready for inclusion in PO file string for headers and all the enrtries
59
	 */
60
	function export($include_headers = true) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
61
		$res = '';
62
		if ($include_headers) {
63
			$res .= $this->export_headers();
64
			$res .= "\n\n";
65
		}
66
		$res .= $this->export_entries();
67
		return $res;
68
	}
69
70
	/**
71
	 * Same as {@link export}, but writes the result to a file
72
	 *
73
	 * @param string $filename where to write the PO string
74
	 * @param bool $include_headers whether to include tje headers in the export
75
	 * @return bool true on success, false on error
76
	 */
77
	function export_to_file($filename, $include_headers = true) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
78
		$fh = fopen($filename, 'w');
79
		if (false === $fh) return false;
80
		$export = $this->export($include_headers);
81
		$res = fwrite($fh, $export);
82
		if (false === $res) return false;
83
		return fclose($fh);
84
	}
85
86
	/**
87
	 * Text to include as a comment before the start of the PO contents
88
	 *
89
	 * Doesn't need to include # in the beginning of lines, these are added automatically
90
	 */
91
	function set_comment_before_headers( $text ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
92
		$this->comments_before_headers = $text;
93
	}
94
95
	/**
96
	 * Formats a string in PO-style
97
	 *
98
	 * @static
99
	 * @param string $string the string to format
100
	 * @return string the poified string
101
	 */
102
	public static function poify($string) {
103
		$quote = '"';
104
		$slash = '\\';
105
		$newline = "\n";
106
107
		$replaces = array(
108
			"$slash" 	=> "$slash$slash",
109
			"$quote"	=> "$slash$quote",
110
			"\t" 		=> '\t',
111
		);
112
113
		$string = str_replace(array_keys($replaces), array_values($replaces), $string);
114
115
		$po = $quote.implode("${slash}n$quote$newline$quote", explode($newline, $string)).$quote;
116
		// add empty string on first line for readbility
117
		if (false !== strpos($string, $newline) &&
118
				(substr_count($string, $newline) > 1 || !($newline === substr($string, -strlen($newline))))) {
119
			$po = "$quote$quote$newline$po";
120
		}
121
		// remove empty strings
122
		$po = str_replace("$newline$quote$quote", '', $po);
123
		return $po;
124
	}
125
126
	/**
127
	 * Gives back the original string from a PO-formatted string
128
	 *
129
	 * @static
130
	 * @param string $string PO-formatted string
131
	 * @return string enascaped string
132
	 */
133
	public static function unpoify($string) {
134
		$escapes = array('t' => "\t", 'n' => "\n", 'r' => "\r", '\\' => '\\');
135
		$lines = array_map('trim', explode("\n", $string));
136
		$lines = array_map(array('PO', 'trim_quotes'), $lines);
137
		$unpoified = '';
138
		$previous_is_backslash = false;
139
		foreach($lines as $line) {
140
			preg_match_all('/./u', $line, $chars);
141
			$chars = $chars[0];
142
			foreach($chars as $char) {
143
				if (!$previous_is_backslash) {
144
					if ('\\' == $char)
145
						$previous_is_backslash = true;
146
					else
147
						$unpoified .= $char;
148
				} else {
149
					$previous_is_backslash = false;
150
					$unpoified .= isset($escapes[$char])? $escapes[$char] : $char;
151
				}
152
			}
153
		}
154
155
		// Standardise the line endings on imported content, technically PO files shouldn't contain \r
156
		$unpoified = str_replace( array( "\r\n", "\r" ), "\n", $unpoified );
157
158
		return $unpoified;
159
	}
160
161
	/**
162
	 * Inserts $with in the beginning of every new line of $string and
163
	 * returns the modified string
164
	 *
165
	 * @static
166
	 * @param string $string prepend lines in this string
167
	 * @param string $with prepend lines with this string
168
	 */
169
	public static function prepend_each_line($string, $with) {
170
		$php_with = var_export($with, true);
171
		$lines = explode("\n", $string);
172
		// do not prepend the string on the last empty line, artefact by explode
173
		if ("\n" == substr($string, -1)) unset($lines[count($lines) - 1]);
174
		$res = implode("\n", array_map(create_function('$x', "return $php_with.\$x;"), $lines));
0 ignored issues
show
Security Best Practice introduced by
The use of create_function is highly discouraged, better use a closure.

create_function can pose a great security vulnerability as it is similar to eval, and could be used for arbitrary code execution. We highly recommend to use a closure instead.

// Instead of
$function = create_function('$a, $b', 'return $a + $b');

// Better use
$function = function($a, $b) { return $a + $b; }
Loading history...
175
		// give back the empty line, we ignored above
176
		if ("\n" == substr($string, -1)) $res .= "\n";
177
		return $res;
178
	}
179
180
	/**
181
	 * Prepare a text as a comment -- wraps the lines and prepends #
182
	 * and a special character to each line
183
	 *
184
	 * @access private
185
	 * @param string $text the comment text
186
	 * @param string $char character to denote a special PO comment,
187
	 * 	like :, default is a space
188
	 */
189
	public static function comment_block($text, $char=' ') {
190
		$text = wordwrap($text, PO_MAX_LINE_LEN - 3);
191
		return PO::prepend_each_line($text, "#$char ");
192
	}
193
194
	/**
195
	 * Builds a string from the entry for inclusion in PO file
196
	 *
197
	 * @static
198
	 * @param Translation_Entry &$entry the entry to convert to po string
199
	 * @return false|string PO-style formatted string for the entry or
200
	 * 	false if the entry is empty
201
	 */
202
	public static function export_entry(&$entry) {
203
		if ( null === $entry->singular || '' === $entry->singular ) return false;
204
		$po = array();
205
		if (!empty($entry->translator_comments)) $po[] = PO::comment_block($entry->translator_comments);
206
		if (!empty($entry->extracted_comments)) $po[] = PO::comment_block($entry->extracted_comments, '.');
207 View Code Duplication
		if (!empty($entry->references)) $po[] = PO::comment_block(implode(' ', $entry->references), ':');
208 View Code Duplication
		if (!empty($entry->flags)) $po[] = PO::comment_block(implode(", ", $entry->flags), ',');
209
		if ($entry->context) $po[] = 'msgctxt '.PO::poify($entry->context);
210
		$po[] = 'msgid '.PO::poify($entry->singular);
211
		if (!$entry->is_plural) {
212
			$translation = empty($entry->translations)? '' : $entry->translations[0];
213
			$translation = PO::match_begin_and_end_newlines( $translation, $entry->singular );
214
			$po[] = 'msgstr '.PO::poify($translation);
215
		} else {
216
			$po[] = 'msgid_plural '.PO::poify($entry->plural);
217
			$translations = empty($entry->translations)? array('', '') : $entry->translations;
218
			foreach($translations as $i => $translation) {
219
				$translation = PO::match_begin_and_end_newlines( $translation, $entry->plural );
220
				$po[] = "msgstr[$i] ".PO::poify($translation);
221
			}
222
		}
223
		return implode("\n", $po);
224
	}
225
226
	public static function match_begin_and_end_newlines( $translation, $original ) {
227
		if ( '' === $translation ) {
228
			return $translation;
229
		}
230
231
		$original_begin = "\n" === substr( $original, 0, 1 );
232
		$original_end = "\n" === substr( $original, -1 );
233
		$translation_begin = "\n" === substr( $translation, 0, 1 );
234
		$translation_end = "\n" === substr( $translation, -1 );
235
236
		if ( $original_begin ) {
237
			if ( ! $translation_begin ) {
238
				$translation = "\n" . $translation;
239
			}
240
		} elseif ( $translation_begin ) {
241
			$translation = ltrim( $translation, "\n" );
242
		}
243
244
		if ( $original_end ) {
245
			if ( ! $translation_end ) {
246
				$translation .= "\n";
247
			}
248
		} elseif ( $translation_end ) {
249
			$translation = rtrim( $translation, "\n" );
250
		}
251
252
		return $translation;
253
	}
254
255
	/**
256
	 * @param string $filename
257
	 * @return boolean
258
	 */
259
	function import_from_file($filename) {
260
		$f = fopen($filename, 'r');
261
		if (!$f) return false;
262
		$lineno = 0;
263
		while (true) {
264
			$res = $this->read_entry($f, $lineno);
265
			if (!$res) break;
0 ignored issues
show
Bug Best Practice introduced by
The expression $res of type array<string,Translation_Entry|integer> is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
266
			if ($res['entry']->singular == '') {
0 ignored issues
show
Bug introduced by
The property singular cannot be accessed from this context as it is declared private in class Translation_Entry.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
267
				$this->set_headers($this->make_headers($res['entry']->translations[0]));
0 ignored issues
show
Bug introduced by
The property translations cannot be accessed from this context as it is declared private in class Translation_Entry.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
268
			} else {
269
				$this->add_entry($res['entry']);
270
			}
271
		}
272
		PO::read_line($f, 'clear');
273
		if ( false === $res ) {
0 ignored issues
show
Bug introduced by
The variable $res does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
274
			return false;
275
		}
276
		if ( ! $this->headers && ! $this->entries ) {
0 ignored issues
show
Bug introduced by
The property headers cannot be accessed from this context as it is declared private in class Translations.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
Bug introduced by
The property entries cannot be accessed from this context as it is declared private in class Translations.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
Bug Best Practice introduced by
The expression $this->headers of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
Bug Best Practice introduced by
The expression $this->entries of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
277
			return false;
278
		}
279
		return true;
280
	}
281
282
	/**
283
	 * @param resource $f
284
	 * @param int      $lineno
285
	 * @return null|false|array
286
	 */
287
	function read_entry($f, $lineno = 0) {
288
		$entry = new Translation_Entry();
289
		// where were we in the last step
290
		// can be: comment, msgctxt, msgid, msgid_plural, msgstr, msgstr_plural
291
		$context = '';
292
		$msgstr_index = 0;
293
		$is_final = create_function('$context', 'return $context == "msgstr" || $context == "msgstr_plural";');
0 ignored issues
show
Security Best Practice introduced by
The use of create_function is highly discouraged, better use a closure.

create_function can pose a great security vulnerability as it is similar to eval, and could be used for arbitrary code execution. We highly recommend to use a closure instead.

// Instead of
$function = create_function('$a, $b', 'return $a + $b');

// Better use
$function = function($a, $b) { return $a + $b; }
Loading history...
294
		while (true) {
295
			$lineno++;
296
			$line = PO::read_line($f);
297
			if (!$line)  {
298
				if (feof($f)) {
299
					if ($is_final($context))
300
						break;
301
					elseif (!$context) // we haven't read a line and eof came
302
						return null;
303
					else
304
						return false;
305
				} else {
306
					return false;
307
				}
308
			}
309
			if ($line == "\n") continue;
310
			$line = trim($line);
311
			if (preg_match('/^#/', $line, $m)) {
312
				// the comment is the start of a new entry
313
				if ($is_final($context)) {
314
					PO::read_line($f, 'put-back');
315
					$lineno--;
316
					break;
317
				}
318
				// comments have to be at the beginning
319
				if ($context && $context != 'comment') {
320
					return false;
321
				}
322
				// add comment
323
				$this->add_comment_to_entry($entry, $line);
324
			} elseif (preg_match('/^msgctxt\s+(".*")/', $line, $m)) {
325
				if ($is_final($context)) {
326
					PO::read_line($f, 'put-back');
327
					$lineno--;
328
					break;
329
				}
330
				if ($context && $context != 'comment') {
331
					return false;
332
				}
333
				$context = 'msgctxt';
334
				$entry->context .= PO::unpoify($m[1]);
0 ignored issues
show
Bug introduced by
The property context cannot be accessed from this context as it is declared private in class Translation_Entry.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
335
			} elseif (preg_match('/^msgid\s+(".*")/', $line, $m)) {
336
				if ($is_final($context)) {
337
					PO::read_line($f, 'put-back');
338
					$lineno--;
339
					break;
340
				}
341
				if ($context && $context != 'msgctxt' && $context != 'comment') {
342
					return false;
343
				}
344
				$context = 'msgid';
345
				$entry->singular .= PO::unpoify($m[1]);
0 ignored issues
show
Bug introduced by
The property singular cannot be accessed from this context as it is declared private in class Translation_Entry.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
346
			} elseif (preg_match('/^msgid_plural\s+(".*")/', $line, $m)) {
347
				if ($context != 'msgid') {
348
					return false;
349
				}
350
				$context = 'msgid_plural';
351
				$entry->is_plural = true;
0 ignored issues
show
Bug introduced by
The property is_plural cannot be accessed from this context as it is declared private in class Translation_Entry.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
352
				$entry->plural .= PO::unpoify($m[1]);
0 ignored issues
show
Bug introduced by
The property plural cannot be accessed from this context as it is declared private in class Translation_Entry.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
353
			} elseif (preg_match('/^msgstr\s+(".*")/', $line, $m)) {
354
				if ($context != 'msgid') {
355
					return false;
356
				}
357
				$context = 'msgstr';
358
				$entry->translations = array(PO::unpoify($m[1]));
0 ignored issues
show
Bug introduced by
The property translations cannot be accessed from this context as it is declared private in class Translation_Entry.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
359
			} elseif (preg_match('/^msgstr\[(\d+)\]\s+(".*")/', $line, $m)) {
360
				if ($context != 'msgid_plural' && $context != 'msgstr_plural') {
361
					return false;
362
				}
363
				$context = 'msgstr_plural';
364
				$msgstr_index = $m[1];
365
				$entry->translations[$m[1]] = PO::unpoify($m[2]);
0 ignored issues
show
Bug introduced by
The property translations cannot be accessed from this context as it is declared private in class Translation_Entry.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
366
			} elseif (preg_match('/^".*"$/', $line)) {
367
				$unpoified = PO::unpoify($line);
368
				switch ($context) {
369
					case 'msgid':
370
						$entry->singular .= $unpoified; break;
0 ignored issues
show
Bug introduced by
The property singular cannot be accessed from this context as it is declared private in class Translation_Entry.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
371
					case 'msgctxt':
372
						$entry->context .= $unpoified; break;
0 ignored issues
show
Bug introduced by
The property context cannot be accessed from this context as it is declared private in class Translation_Entry.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
373
					case 'msgid_plural':
374
						$entry->plural .= $unpoified; break;
0 ignored issues
show
Bug introduced by
The property plural cannot be accessed from this context as it is declared private in class Translation_Entry.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
375
					case 'msgstr':
376
						$entry->translations[0] .= $unpoified; break;
0 ignored issues
show
Bug introduced by
The property translations cannot be accessed from this context as it is declared private in class Translation_Entry.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
377
					case 'msgstr_plural':
378
						$entry->translations[$msgstr_index] .= $unpoified; break;
0 ignored issues
show
Bug introduced by
The property translations cannot be accessed from this context as it is declared private in class Translation_Entry.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
379
					default:
380
						return false;
381
				}
382
			} else {
383
				return false;
384
			}
385
		}
386
		if (array() == array_filter($entry->translations, create_function('$t', 'return $t || "0" === $t;'))) {
0 ignored issues
show
Bug introduced by
The property translations cannot be accessed from this context as it is declared private in class Translation_Entry.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
Security Best Practice introduced by
The use of create_function is highly discouraged, better use a closure.

create_function can pose a great security vulnerability as it is similar to eval, and could be used for arbitrary code execution. We highly recommend to use a closure instead.

// Instead of
$function = create_function('$a, $b', 'return $a + $b');

// Better use
$function = function($a, $b) { return $a + $b; }
Loading history...
387
			$entry->translations = array();
0 ignored issues
show
Bug introduced by
The property translations cannot be accessed from this context as it is declared private in class Translation_Entry.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
388
		}
389
		return array('entry' => $entry, 'lineno' => $lineno);
390
	}
391
392
	/**
393
	 * @staticvar string   $last_line
394
	 * @staticvar boolean  $use_last_line
395
	 *
396
	 * @param     resource $f
397
	 * @param     string   $action
398
	 * @return boolean
399
	 */
400
	function read_line($f, $action = 'read') {
401
		static $last_line = '';
402
		static $use_last_line = false;
403
		if ('clear' == $action) {
404
			$last_line = '';
405
			return true;
406
		}
407
		if ('put-back' == $action) {
408
			$use_last_line = true;
409
			return true;
410
		}
411
		$line = $use_last_line? $last_line : fgets($f);
412
		$line = ( "\r\n" == substr( $line, -2 ) ) ? rtrim( $line, "\r\n" ) . "\n" : $line;
413
		$last_line = $line;
414
		$use_last_line = false;
415
		return $line;
416
	}
417
418
	/**
419
	 * @param Translation_Entry $entry
420
	 * @param string            $po_comment_line
421
	 */
422
	function add_comment_to_entry(&$entry, $po_comment_line) {
423
		$first_two = substr($po_comment_line, 0, 2);
424
		$comment = trim(substr($po_comment_line, 2));
425
		if ('#:' == $first_two) {
426
			$entry->references = array_merge($entry->references, preg_split('/\s+/', $comment));
0 ignored issues
show
Bug introduced by
The property references cannot be accessed from this context as it is declared private in class Translation_Entry.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
427
		} elseif ('#.' == $first_two) {
428
			$entry->extracted_comments = trim($entry->extracted_comments . "\n" . $comment);
0 ignored issues
show
Bug introduced by
The property extracted_comments cannot be accessed from this context as it is declared private in class Translation_Entry.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
429
		} elseif ('#,' == $first_two) {
430
			$entry->flags = array_merge($entry->flags, preg_split('/,\s*/', $comment));
0 ignored issues
show
Bug introduced by
The property flags cannot be accessed from this context as it is declared private in class Translation_Entry.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
431
		} else {
432
			$entry->translator_comments = trim($entry->translator_comments . "\n" . $comment);
0 ignored issues
show
Bug introduced by
The property translator_comments cannot be accessed from this context as it is declared private in class Translation_Entry.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
433
		}
434
	}
435
436
	/**
437
	 * @param string $s
438
	 * @return sring
439
	 */
440
	public static function trim_quotes($s) {
441
		if ( substr($s, 0, 1) == '"') $s = substr($s, 1);
442
		if ( substr($s, -1, 1) == '"') $s = substr($s, 0, -1);
443
		return $s;
444
	}
445
}
446
endif;
447