[ Index ]

PHP Cross Reference of MediaWiki-1.24.0

title

Body

[close]

/includes/media/ -> XMPValidate.php (source)

   1  <?php
   2  /**
   3   * Methods for validating XMP properties.
   4   *
   5   * This program is free software; you can redistribute it and/or modify
   6   * it under the terms of the GNU General Public License as published by
   7   * the Free Software Foundation; either version 2 of the License, or
   8   * (at your option) any later version.
   9   *
  10   * This program is distributed in the hope that it will be useful,
  11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13   * GNU General Public License for more details.
  14   *
  15   * You should have received a copy of the GNU General Public License along
  16   * with this program; if not, write to the Free Software Foundation, Inc.,
  17   * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  18   * http://www.gnu.org/copyleft/gpl.html
  19   *
  20   * @file
  21   * @ingroup Media
  22   */
  23  
  24  /**
  25   * This contains some static methods for
  26   * validating XMP properties. See XMPInfo and XMPReader classes.
  27   *
  28   * Each of these functions take the same parameters
  29   * * an info array which is a subset of the XMPInfo::items array
  30   * * A value (passed as reference) to validate. This can be either a
  31   *    simple value or an array
  32   * * A boolean to determine if this is validating a simple or complex values
  33   *
  34   * It should be noted that when an array is being validated, typically the validation
  35   * function is called once for each value, and then once at the end for the entire array.
  36   *
  37   * These validation functions can also be used to modify the data. See the gps and flash one's
  38   * for example.
  39   *
  40   * @see http://www.adobe.com/devnet/xmp/pdfs/XMPSpecificationPart1.pdf starting at pg 28
  41   * @see http://www.adobe.com/devnet/xmp/pdfs/XMPSpecificationPart2.pdf starting at pg 11
  42   */
  43  class XMPValidate {
  44      /**
  45       * Function to validate boolean properties ( True or False )
  46       *
  47       * @param array $info Information about current property
  48       * @param mixed &$val Current value to validate
  49       * @param bool $standalone If this is a simple property or array
  50       */
  51  	public static function validateBoolean( $info, &$val, $standalone ) {
  52          if ( !$standalone ) {
  53              // this only validates standalone properties, not arrays, etc
  54              return;
  55          }
  56          if ( $val !== 'True' && $val !== 'False' ) {
  57              wfDebugLog( 'XMP', __METHOD__ . " Expected True or False but got $val" );
  58              $val = null;
  59          }
  60      }
  61  
  62      /**
  63       * function to validate rational properties ( 12/10 )
  64       *
  65       * @param array $info Information about current property
  66       * @param mixed &$val Current value to validate
  67       * @param bool $standalone If this is a simple property or array
  68       */
  69  	public static function validateRational( $info, &$val, $standalone ) {
  70          if ( !$standalone ) {
  71              // this only validates standalone properties, not arrays, etc
  72              return;
  73          }
  74          if ( !preg_match( '/^(?:-?\d+)\/(?:\d+[1-9]|[1-9]\d*)$/D', $val ) ) {
  75              wfDebugLog( 'XMP', __METHOD__ . " Expected rational but got $val" );
  76              $val = null;
  77          }
  78      }
  79  
  80      /**
  81       * function to validate rating properties -1, 0-5
  82       *
  83       * if its outside of range put it into range.
  84       *
  85       * @see MWG spec
  86       * @param array $info Information about current property
  87       * @param mixed &$val Current value to validate
  88       * @param bool $standalone If this is a simple property or array
  89       */
  90  	public static function validateRating( $info, &$val, $standalone ) {
  91          if ( !$standalone ) {
  92              // this only validates standalone properties, not arrays, etc
  93              return;
  94          }
  95          if ( !preg_match( '/^[-+]?\d*(?:\.?\d*)$/D', $val )
  96              || !is_numeric( $val )
  97          ) {
  98              wfDebugLog( 'XMP', __METHOD__ . " Expected rating but got $val" );
  99              $val = null;
 100  
 101              return;
 102          } else {
 103              $nVal = (float)$val;
 104              if ( $nVal < 0 ) {
 105                  // We do < 0 here instead of < -1 here, since
 106                  // the values between 0 and -1 are also illegal
 107                  // as -1 is meant as a special reject rating.
 108                  wfDebugLog( 'XMP', __METHOD__ . " Rating too low, setting to -1 (Rejected)" );
 109                  $val = '-1';
 110  
 111                  return;
 112              }
 113              if ( $nVal > 5 ) {
 114                  wfDebugLog( 'XMP', __METHOD__ . " Rating too high, setting to 5" );
 115                  $val = '5';
 116  
 117                  return;
 118              }
 119          }
 120      }
 121  
 122      /**
 123       * function to validate integers
 124       *
 125       * @param array $info Information about current property
 126       * @param mixed &$val Current value to validate
 127       * @param bool $standalone If this is a simple property or array
 128       */
 129  	public static function validateInteger( $info, &$val, $standalone ) {
 130          if ( !$standalone ) {
 131              // this only validates standalone properties, not arrays, etc
 132              return;
 133          }
 134          if ( !preg_match( '/^[-+]?\d+$/D', $val ) ) {
 135              wfDebugLog( 'XMP', __METHOD__ . " Expected integer but got $val" );
 136              $val = null;
 137          }
 138      }
 139  
 140      /**
 141       * function to validate properties with a fixed number of allowed
 142       * choices. (closed choice)
 143       *
 144       * @param array $info Information about current property
 145       * @param mixed &$val Current value to validate
 146       * @param bool $standalone If this is a simple property or array
 147       */
 148  	public static function validateClosed( $info, &$val, $standalone ) {
 149          if ( !$standalone ) {
 150              // this only validates standalone properties, not arrays, etc
 151              return;
 152          }
 153  
 154          //check if its in a numeric range
 155          $inRange = false;
 156          if ( isset( $info['rangeLow'] )
 157              && isset( $info['rangeHigh'] )
 158              && is_numeric( $val )
 159              && ( intval( $val ) <= $info['rangeHigh'] )
 160              && ( intval( $val ) >= $info['rangeLow'] )
 161          ) {
 162              $inRange = true;
 163          }
 164  
 165          if ( !isset( $info['choices'][$val] ) && !$inRange ) {
 166              wfDebugLog( 'XMP', __METHOD__ . " Expected closed choice, but got $val" );
 167              $val = null;
 168          }
 169      }
 170  
 171      /**
 172       * function to validate and modify flash structure
 173       *
 174       * @param array $info Information about current property
 175       * @param mixed &$val Current value to validate
 176       * @param bool $standalone If this is a simple property or array
 177       */
 178  	public static function validateFlash( $info, &$val, $standalone ) {
 179          if ( $standalone ) {
 180              // this only validates flash structs, not individual properties
 181              return;
 182          }
 183          if ( !( isset( $val['Fired'] )
 184              && isset( $val['Function'] )
 185              && isset( $val['Mode'] )
 186              && isset( $val['RedEyeMode'] )
 187              && isset( $val['Return'] )
 188          ) ) {
 189              wfDebugLog( 'XMP', __METHOD__ . " Flash structure did not have all the required components" );
 190              $val = null;
 191          } else {
 192              $val = ( "\0" | ( $val['Fired'] === 'True' )
 193                  | ( intval( $val['Return'] ) << 1 )
 194                  | ( intval( $val['Mode'] ) << 3 )
 195                  | ( ( $val['Function'] === 'True' ) << 5 )
 196                  | ( ( $val['RedEyeMode'] === 'True' ) << 6 ) );
 197          }
 198      }
 199  
 200      /**
 201       * function to validate LangCode properties ( en-GB, etc )
 202       *
 203       * This is just a naive check to make sure it somewhat looks like a lang code.
 204       *
 205       * @see rfc 3066
 206       * @see http://www.adobe.com/devnet/xmp/pdfs/XMPSpecificationPart1.pdf page 30 (section 8.2.2.5)
 207       *
 208       * @param array $info Information about current property
 209       * @param mixed &$val Current value to validate
 210       * @param bool $standalone If this is a simple property or array
 211       */
 212  	public static function validateLangCode( $info, &$val, $standalone ) {
 213          if ( !$standalone ) {
 214              // this only validates standalone properties, not arrays, etc
 215              return;
 216          }
 217          if ( !preg_match( '/^[-A-Za-z0-9]{2,}$/D', $val ) ) {
 218              //this is a rather naive check.
 219              wfDebugLog( 'XMP', __METHOD__ . " Expected Lang code but got $val" );
 220              $val = null;
 221          }
 222      }
 223  
 224      /**
 225       * function to validate date properties, and convert to (partial) Exif format.
 226       *
 227       * Dates can be one of the following formats:
 228       * YYYY
 229       * YYYY-MM
 230       * YYYY-MM-DD
 231       * YYYY-MM-DDThh:mmTZD
 232       * YYYY-MM-DDThh:mm:ssTZD
 233       * YYYY-MM-DDThh:mm:ss.sTZD
 234       *
 235       * @param array $info Information about current property
 236       * @param mixed &$val Current value to validate. Converts to TS_EXIF as a side-effect.
 237       *    in cases where there's only a partial date, it will give things like
 238       *    2011:04.
 239       * @param bool $standalone If this is a simple property or array
 240       */
 241  	public static function validateDate( $info, &$val, $standalone ) {
 242          if ( !$standalone ) {
 243              // this only validates standalone properties, not arrays, etc
 244              return;
 245          }
 246          $res = array();
 247          // @codingStandardsIgnoreStart Long line that cannot be broken
 248          if ( !preg_match(
 249              /* ahh! scary regex... */
 250              '/^([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',
 251              $val, $res )
 252          ) {
 253              // @codingStandardsIgnoreEnd
 254  
 255              wfDebugLog( 'XMP', __METHOD__ . " Expected date but got $val" );
 256              $val = null;
 257          } else {
 258              /*
 259               * $res is formatted as follows:
 260               * 0 -> full date.
 261               * 1 -> year, 2-> month, 3-> day, 4-> hour, 5-> minute, 6->second
 262               * 7-> Timezone specifier (Z or something like +12:30 )
 263               * many parts are optional, some aren't. For example if you specify
 264               * minute, you must specify hour, day, month, and year but not second or TZ.
 265               */
 266  
 267              /*
 268               * First of all, if year = 0000, Something is wrongish,
 269               * so don't extract. This seems to happen when
 270               * some programs convert between metadata formats.
 271               */
 272              if ( $res[1] === '0000' ) {
 273                  wfDebugLog( 'XMP', __METHOD__ . " Invalid date (year 0): $val" );
 274                  $val = null;
 275  
 276                  return;
 277              }
 278  
 279              if ( !isset( $res[4] ) ) { //hour
 280                  //just have the year month day (if that)
 281                  $val = $res[1];
 282                  if ( isset( $res[2] ) ) {
 283                      $val .= ':' . $res[2];
 284                  }
 285                  if ( isset( $res[3] ) ) {
 286                      $val .= ':' . $res[3];
 287                  }
 288  
 289                  return;
 290              }
 291  
 292              if ( !isset( $res[7] ) || $res[7] === 'Z' ) {
 293                  //if hour is set, then minute must also be or regex above will fail.
 294                  $val = $res[1] . ':' . $res[2] . ':' . $res[3]
 295                      . ' ' . $res[4] . ':' . $res[5];
 296                  if ( isset( $res[6] ) && $res[6] !== '' ) {
 297                      $val .= ':' . $res[6];
 298                  }
 299  
 300                  return;
 301              }
 302  
 303              // Extra check for empty string necessary due to TZ but no second case.
 304              $stripSeconds = false;
 305              if ( !isset( $res[6] ) || $res[6] === '' ) {
 306                  $res[6] = '00';
 307                  $stripSeconds = true;
 308              }
 309  
 310              // Do timezone processing. We've already done the case that tz = Z.
 311  
 312              // We know that if we got to this step, year, month day hour and min must be set
 313              // by virtue of regex not failing.
 314  
 315              $unix = wfTimestamp( TS_UNIX, $res[1] . $res[2] . $res[3] . $res[4] . $res[5] . $res[6] );
 316              $offset = intval( substr( $res[7], 1, 2 ) ) * 60 * 60;
 317              $offset += intval( substr( $res[7], 4, 2 ) ) * 60;
 318              if ( substr( $res[7], 0, 1 ) === '-' ) {
 319                  $offset = -$offset;
 320              }
 321              $val = wfTimestamp( TS_EXIF, $unix + $offset );
 322  
 323              if ( $stripSeconds ) {
 324                  // If seconds weren't specified, remove the trailing ':00'.
 325                  $val = substr( $val, 0, -3 );
 326              }
 327          }
 328      }
 329  
 330      /** function to validate, and more importantly
 331       * translate the XMP DMS form of gps coords to
 332       * the decimal form we use.
 333       *
 334       * @see http://www.adobe.com/devnet/xmp/pdfs/XMPSpecificationPart2.pdf
 335       *        section 1.2.7.4 on page 23
 336       *
 337       * @param array $info Unused (info about prop)
 338       * @param string &$val GPS string in either DDD,MM,SSk or
 339       *   or DDD,MM.mmk form
 340       * @param bool $standalone If its a simple prop (should always be true)
 341       */
 342  	public static function validateGPS( $info, &$val, $standalone ) {
 343          if ( !$standalone ) {
 344              return;
 345          }
 346  
 347          $m = array();
 348          if ( preg_match(
 349              '/(\d{1,3}),(\d{1,2}),(\d{1,2})([NWSE])/D',
 350              $val, $m )
 351          ) {
 352              $coord = intval( $m[1] );
 353              $coord += intval( $m[2] ) * ( 1 / 60 );
 354              $coord += intval( $m[3] ) * ( 1 / 3600 );
 355              if ( $m[4] === 'S' || $m[4] === 'W' ) {
 356                  $coord = -$coord;
 357              }
 358              $val = $coord;
 359  
 360              return;
 361          } elseif ( preg_match(
 362              '/(\d{1,3}),(\d{1,2}(?:.\d*)?)([NWSE])/D',
 363              $val, $m )
 364          ) {
 365              $coord = intval( $m[1] );
 366              $coord += floatval( $m[2] ) * ( 1 / 60 );
 367              if ( $m[3] === 'S' || $m[3] === 'W' ) {
 368                  $coord = -$coord;
 369              }
 370              $val = $coord;
 371  
 372              return;
 373          } else {
 374              wfDebugLog( 'XMP', __METHOD__
 375                  . " Expected GPSCoordinate, but got $val." );
 376              $val = null;
 377  
 378              return;
 379          }
 380      }
 381  }


Generated: Fri Nov 28 14:03:12 2014 Cross-referenced by PHPXref 0.7.1