MediaWiki  REL1_31
XMPValidate.php
Go to the documentation of this file.
1 <?php
24 use Psr\Log\LoggerInterface;
25 use Psr\Log\LoggerAwareInterface;
26 use Wikimedia\Timestamp\ConvertibleTimestamp;
27 
47 class XMPValidate implements LoggerAwareInterface {
48 
52  private $logger;
53 
54  public function __construct( LoggerInterface $logger ) {
55  $this->setLogger( $logger );
56  }
57 
58  public function setLogger( LoggerInterface $logger ) {
59  $this->logger = $logger;
60  }
68  public function validateBoolean( $info, &$val, $standalone ) {
69  if ( !$standalone ) {
70  // this only validates standalone properties, not arrays, etc
71  return;
72  }
73  if ( $val !== 'True' && $val !== 'False' ) {
74  $this->logger->info( __METHOD__ . " Expected True or False but got $val" );
75  $val = null;
76  }
77  }
78 
86  public function validateRational( $info, &$val, $standalone ) {
87  if ( !$standalone ) {
88  // this only validates standalone properties, not arrays, etc
89  return;
90  }
91  if ( !preg_match( '/^(?:-?\d+)\/(?:\d+[1-9]|[1-9]\d*)$/D', $val ) ) {
92  $this->logger->info( __METHOD__ . " Expected rational but got $val" );
93  $val = null;
94  }
95  }
96 
107  public function validateRating( $info, &$val, $standalone ) {
108  if ( !$standalone ) {
109  // this only validates standalone properties, not arrays, etc
110  return;
111  }
112  if ( !preg_match( '/^[-+]?\d*(?:\.?\d*)$/D', $val )
113  || !is_numeric( $val )
114  ) {
115  $this->logger->info( __METHOD__ . " Expected rating but got $val" );
116  $val = null;
117 
118  return;
119  } else {
120  $nVal = (float)$val;
121  if ( $nVal < 0 ) {
122  // We do < 0 here instead of < -1 here, since
123  // the values between 0 and -1 are also illegal
124  // as -1 is meant as a special reject rating.
125  $this->logger->info( __METHOD__ . " Rating too low, setting to -1 (Rejected)" );
126  $val = '-1';
127 
128  return;
129  }
130  if ( $nVal > 5 ) {
131  $this->logger->info( __METHOD__ . " Rating too high, setting to 5" );
132  $val = '5';
133 
134  return;
135  }
136  }
137  }
138 
146  public function validateInteger( $info, &$val, $standalone ) {
147  if ( !$standalone ) {
148  // this only validates standalone properties, not arrays, etc
149  return;
150  }
151  if ( !preg_match( '/^[-+]?\d+$/D', $val ) ) {
152  $this->logger->info( __METHOD__ . " Expected integer but got $val" );
153  $val = null;
154  }
155  }
156 
165  public function validateClosed( $info, &$val, $standalone ) {
166  if ( !$standalone ) {
167  // this only validates standalone properties, not arrays, etc
168  return;
169  }
170 
171  // check if its in a numeric range
172  $inRange = false;
173  if ( isset( $info['rangeLow'] )
174  && isset( $info['rangeHigh'] )
175  && is_numeric( $val )
176  && ( intval( $val ) <= $info['rangeHigh'] )
177  && ( intval( $val ) >= $info['rangeLow'] )
178  ) {
179  $inRange = true;
180  }
181 
182  if ( !isset( $info['choices'][$val] ) && !$inRange ) {
183  $this->logger->info( __METHOD__ . " Expected closed choice, but got $val" );
184  $val = null;
185  }
186  }
187 
195  public function validateFlash( $info, &$val, $standalone ) {
196  if ( $standalone ) {
197  // this only validates flash structs, not individual properties
198  return;
199  }
200  if ( !( isset( $val['Fired'] )
201  && isset( $val['Function'] )
202  && isset( $val['Mode'] )
203  && isset( $val['RedEyeMode'] )
204  && isset( $val['Return'] )
205  ) ) {
206  $this->logger->info( __METHOD__ . " Flash structure did not have all the required components" );
207  $val = null;
208  } else {
209  $val = ( 0 | ( $val['Fired'] === 'True' )
210  | ( intval( $val['Return'] ) << 1 )
211  | ( intval( $val['Mode'] ) << 3 )
212  | ( ( $val['Function'] === 'True' ) << 5 )
213  | ( ( $val['RedEyeMode'] === 'True' ) << 6 ) );
214  }
215  }
216 
230  public function validateLangCode( $info, &$val, $standalone ) {
231  if ( !$standalone ) {
232  // this only validates standalone properties, not arrays, etc
233  return;
234  }
235  if ( !preg_match( '/^[-A-Za-z0-9]{2,}$/D', $val ) ) {
236  // this is a rather naive check.
237  $this->logger->info( __METHOD__ . " Expected Lang code but got $val" );
238  $val = null;
239  }
240  }
241 
259  public function validateDate( $info, &$val, $standalone ) {
260  if ( !$standalone ) {
261  // this only validates standalone properties, not arrays, etc
262  return;
263  }
264  $res = [];
265  if ( !preg_match(
266  /* ahh! scary regex... */
267  // phpcs:ignore Generic.Files.LineLength
268  '/^([0-3]\d{3})(?:-([01]\d)(?:-([0-3]\d)(?:T([0-2]\d):([0-6]\d)(?::([0-6]\d)(?:\.\d+)?)?([-+]\d{2}:\d{2}|Z)?)?)?)?$/D',
269  $val, $res )
270  ) {
271  $this->logger->info( __METHOD__ . " Expected date but got $val" );
272  $val = null;
273  } else {
274  /*
275  * $res is formatted as follows:
276  * 0 -> full date.
277  * 1 -> year, 2-> month, 3-> day, 4-> hour, 5-> minute, 6->second
278  * 7-> Timezone specifier (Z or something like +12:30 )
279  * many parts are optional, some aren't. For example if you specify
280  * minute, you must specify hour, day, month, and year but not second or TZ.
281  */
282 
283  /*
284  * First of all, if year = 0000, Something is wrongish,
285  * so don't extract. This seems to happen when
286  * some programs convert between metadata formats.
287  */
288  if ( $res[1] === '0000' ) {
289  $this->logger->info( __METHOD__ . " Invalid date (year 0): $val" );
290  $val = null;
291 
292  return;
293  }
294 
295  if ( !isset( $res[4] ) ) { // hour
296  // just have the year month day (if that)
297  $val = $res[1];
298  if ( isset( $res[2] ) ) {
299  $val .= ':' . $res[2];
300  }
301  if ( isset( $res[3] ) ) {
302  $val .= ':' . $res[3];
303  }
304 
305  return;
306  }
307 
308  if ( !isset( $res[7] ) || $res[7] === 'Z' ) {
309  // if hour is set, then minute must also be or regex above will fail.
310  $val = $res[1] . ':' . $res[2] . ':' . $res[3]
311  . ' ' . $res[4] . ':' . $res[5];
312  if ( isset( $res[6] ) && $res[6] !== '' ) {
313  $val .= ':' . $res[6];
314  }
315 
316  return;
317  }
318 
319  // Extra check for empty string necessary due to TZ but no second case.
320  $stripSeconds = false;
321  if ( !isset( $res[6] ) || $res[6] === '' ) {
322  $res[6] = '00';
323  $stripSeconds = true;
324  }
325 
326  // Do timezone processing. We've already done the case that tz = Z.
327 
328  // We know that if we got to this step, year, month day hour and min must be set
329  // by virtue of regex not failing.
330 
331  $unix = ConvertibleTimestamp::convert( TS_UNIX,
332  $res[1] . $res[2] . $res[3] . $res[4] . $res[5] . $res[6]
333  );
334  $offset = intval( substr( $res[7], 1, 2 ) ) * 60 * 60;
335  $offset += intval( substr( $res[7], 4, 2 ) ) * 60;
336  if ( substr( $res[7], 0, 1 ) === '-' ) {
337  $offset = -$offset;
338  }
339  $val = ConvertibleTimestamp::convert( TS_EXIF, $unix + $offset );
340 
341  if ( $stripSeconds ) {
342  // If seconds weren't specified, remove the trailing ':00'.
343  $val = substr( $val, 0, -3 );
344  }
345  }
346  }
347 
360  public function validateGPS( $info, &$val, $standalone ) {
361  if ( !$standalone ) {
362  return;
363  }
364 
365  $m = [];
366  if ( preg_match(
367  '/(\d{1,3}),(\d{1,2}),(\d{1,2})([NWSE])/D',
368  $val, $m )
369  ) {
370  $coord = intval( $m[1] );
371  $coord += intval( $m[2] ) * ( 1 / 60 );
372  $coord += intval( $m[3] ) * ( 1 / 3600 );
373  if ( $m[4] === 'S' || $m[4] === 'W' ) {
374  $coord = -$coord;
375  }
376  $val = $coord;
377 
378  return;
379  } elseif ( preg_match(
380  '/(\d{1,3}),(\d{1,2}(?:.\d*)?)([NWSE])/D',
381  $val, $m )
382  ) {
383  $coord = intval( $m[1] );
384  $coord += floatval( $m[2] ) * ( 1 / 60 );
385  if ( $m[3] === 'S' || $m[3] === 'W' ) {
386  $coord = -$coord;
387  }
388  $val = $coord;
389 
390  return;
391  } else {
392  $this->logger->info( __METHOD__
393  . " Expected GPSCoordinate, but got $val." );
394  $val = null;
395 
396  return;
397  }
398  }
399 }
use
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for use
Definition: APACHE-LICENSE-2.0.txt:10
XMPValidate\setLogger
setLogger(LoggerInterface $logger)
Definition: XMPValidate.php:58
XMPValidate\$logger
LoggerInterface $logger
Definition: XMPValidate.php:52
$res
$res
Definition: database.txt:21
php
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:37
XMPValidate\validateClosed
validateClosed( $info, &$val, $standalone)
function to validate properties with a fixed number of allowed choices.
Definition: XMPValidate.php:165
XMPValidate\validateFlash
validateFlash( $info, &$val, $standalone)
function to validate and modify flash structure
Definition: XMPValidate.php:195
XMPValidate\__construct
__construct(LoggerInterface $logger)
Definition: XMPValidate.php:54
XMPValidate\validateGPS
validateGPS( $info, &$val, $standalone)
function to validate, and more importantly translate the XMP DMS form of gps coords to the decimal fo...
Definition: XMPValidate.php:360
XMPValidate\validateInteger
validateInteger( $info, &$val, $standalone)
function to validate integers
Definition: XMPValidate.php:146
XMPValidate\validateRational
validateRational( $info, &$val, $standalone)
function to validate rational properties ( 12/10 )
Definition: XMPValidate.php:86
XMPValidate\validateBoolean
validateBoolean( $info, &$val, $standalone)
Function to validate boolean properties ( True or False )
Definition: XMPValidate.php:68
XMPValidate\validateRating
validateRating( $info, &$val, $standalone)
function to validate rating properties -1, 0-5
Definition: XMPValidate.php:107
XMPValidate
This contains some static methods for validating XMP properties.
Definition: XMPValidate.php:47
XMPValidate\validateDate
validateDate( $info, &$val, $standalone)
function to validate date properties, and convert to (partial) Exif format.
Definition: XMPValidate.php:259
XMPValidate\validateLangCode
validateLangCode( $info, &$val, $standalone)
function to validate LangCode properties ( en-GB, etc )
Definition: XMPValidate.php:230