MediaWiki  1.29.1
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  // @codingStandardsIgnoreStart Long line that cannot be broken
266  if ( !preg_match(
267  /* ahh! scary regex... */
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  // @codingStandardsIgnoreEnd
272 
273  $this->logger->info( __METHOD__ . " Expected date but got $val" );
274  $val = null;
275  } else {
276  /*
277  * $res is formatted as follows:
278  * 0 -> full date.
279  * 1 -> year, 2-> month, 3-> day, 4-> hour, 5-> minute, 6->second
280  * 7-> Timezone specifier (Z or something like +12:30 )
281  * many parts are optional, some aren't. For example if you specify
282  * minute, you must specify hour, day, month, and year but not second or TZ.
283  */
284 
285  /*
286  * First of all, if year = 0000, Something is wrongish,
287  * so don't extract. This seems to happen when
288  * some programs convert between metadata formats.
289  */
290  if ( $res[1] === '0000' ) {
291  $this->logger->info( __METHOD__ . " Invalid date (year 0): $val" );
292  $val = null;
293 
294  return;
295  }
296 
297  if ( !isset( $res[4] ) ) { // hour
298  // just have the year month day (if that)
299  $val = $res[1];
300  if ( isset( $res[2] ) ) {
301  $val .= ':' . $res[2];
302  }
303  if ( isset( $res[3] ) ) {
304  $val .= ':' . $res[3];
305  }
306 
307  return;
308  }
309 
310  if ( !isset( $res[7] ) || $res[7] === 'Z' ) {
311  // if hour is set, then minute must also be or regex above will fail.
312  $val = $res[1] . ':' . $res[2] . ':' . $res[3]
313  . ' ' . $res[4] . ':' . $res[5];
314  if ( isset( $res[6] ) && $res[6] !== '' ) {
315  $val .= ':' . $res[6];
316  }
317 
318  return;
319  }
320 
321  // Extra check for empty string necessary due to TZ but no second case.
322  $stripSeconds = false;
323  if ( !isset( $res[6] ) || $res[6] === '' ) {
324  $res[6] = '00';
325  $stripSeconds = true;
326  }
327 
328  // Do timezone processing. We've already done the case that tz = Z.
329 
330  // We know that if we got to this step, year, month day hour and min must be set
331  // by virtue of regex not failing.
332 
333  $unix = ConvertibleTimestamp::convert( TS_UNIX,
334  $res[1] . $res[2] . $res[3] . $res[4] . $res[5] . $res[6]
335  );
336  $offset = intval( substr( $res[7], 1, 2 ) ) * 60 * 60;
337  $offset += intval( substr( $res[7], 4, 2 ) ) * 60;
338  if ( substr( $res[7], 0, 1 ) === '-' ) {
339  $offset = -$offset;
340  }
341  $val = ConvertibleTimestamp::convert( TS_EXIF, $unix + $offset );
342 
343  if ( $stripSeconds ) {
344  // If seconds weren't specified, remove the trailing ':00'.
345  $val = substr( $val, 0, -3 );
346  }
347  }
348  }
349 
362  public function validateGPS( $info, &$val, $standalone ) {
363  if ( !$standalone ) {
364  return;
365  }
366 
367  $m = [];
368  if ( preg_match(
369  '/(\d{1,3}),(\d{1,2}),(\d{1,2})([NWSE])/D',
370  $val, $m )
371  ) {
372  $coord = intval( $m[1] );
373  $coord += intval( $m[2] ) * ( 1 / 60 );
374  $coord += intval( $m[3] ) * ( 1 / 3600 );
375  if ( $m[4] === 'S' || $m[4] === 'W' ) {
376  $coord = -$coord;
377  }
378  $val = $coord;
379 
380  return;
381  } elseif ( preg_match(
382  '/(\d{1,3}),(\d{1,2}(?:.\d*)?)([NWSE])/D',
383  $val, $m )
384  ) {
385  $coord = intval( $m[1] );
386  $coord += floatval( $m[2] ) * ( 1 / 60 );
387  if ( $m[3] === 'S' || $m[3] === 'W' ) {
388  $coord = -$coord;
389  }
390  $val = $coord;
391 
392  return;
393  } else {
394  $this->logger->info( __METHOD__
395  . " Expected GPSCoordinate, but got $val." );
396  $val = null;
397 
398  return;
399  }
400  }
401 }
XMPValidate\setLogger
setLogger(LoggerInterface $logger)
Definition: XMPValidate.php:58
use
as see the revision history and available at free of to any person obtaining a copy of this software and associated documentation to deal in the Software without including without limitation the rights to use
Definition: MIT-LICENSE.txt:10
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:35
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:362
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