Index: trunk/extensions/DonationInterface/gateway_common/DataValidator.php |
— | — | @@ -0,0 +1,676 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * DataValidator |
| 6 | + * This class is responsible for performing all kinds of data validation, |
| 7 | + * wherever we may need it. |
| 8 | + * |
| 9 | + * All functions should be static, so we don't have to construct anything in |
| 10 | + * order to use it any/everywhere. |
| 11 | + * |
| 12 | + * @author khorn |
| 13 | + */ |
| 14 | +class DataValidator { |
| 15 | + |
| 16 | + /** |
| 17 | + * $boolean_fields |
| 18 | + * @var array All fields that should validate as boolean values |
| 19 | + */ |
| 20 | + protected static $boolean_fields = array( |
| 21 | + 'comment-option', |
| 22 | + 'email-opt', |
| 23 | + '_cache_', |
| 24 | + 'anonymous', |
| 25 | + 'optout', |
| 26 | + 'recurring', |
| 27 | + 'posted', |
| 28 | + ); |
| 29 | + |
| 30 | + /** |
| 31 | + * $numeric_fields |
| 32 | + * @var array All fields that should validate as numeric |
| 33 | + */ |
| 34 | + protected static $numeric_fields = array( |
| 35 | + 'amount', |
| 36 | + 'amountGiven', |
| 37 | + 'amountOther', |
| 38 | + 'cvv', |
| 39 | + 'contribution_tracking_id', |
| 40 | + 'account_number', |
| 41 | + 'expiration', |
| 42 | + 'order_id', |
| 43 | + 'i_order_id', |
| 44 | + 'numAttempt' |
| 45 | + ); |
| 46 | + |
| 47 | + /** |
| 48 | + * $gateway_classes |
| 49 | + * @var array A list of all possible gateway classes. |
| 50 | + */ |
| 51 | + protected static $gateway_classes = array( |
| 52 | + 'globalcollect' => 'GlobalCollectAdapter', |
| 53 | + 'payflowpro' => 'PayflowProAdapter' |
| 54 | + ); |
| 55 | + |
| 56 | + /** |
| 57 | + * $card_types |
| 58 | + * @var array A list of all card types we recognize |
| 59 | + */ |
| 60 | + protected static $card_types = array( |
| 61 | + 'american', |
| 62 | + 'mastercard', |
| 63 | + 'visa', |
| 64 | + 'discover' |
| 65 | + ); |
| 66 | + |
| 67 | + |
| 68 | + /** |
| 69 | + * getNumericFields returns a list of DonationInterface fields that are |
| 70 | + * expected to contain numeric values. |
| 71 | + * @return array A non-ordered array of field names. |
| 72 | + */ |
| 73 | + public static function getNumericFields(){ |
| 74 | + return self::$numeric_fields; |
| 75 | + } |
| 76 | + |
| 77 | + |
| 78 | + /** |
| 79 | + * getBooleanFields returns a list of DonationInterface fields that are |
| 80 | + * expected to contain boolean values. |
| 81 | + * @return array A non-ordered array of field names. |
| 82 | + */ |
| 83 | + public static function getBooleanFields(){ |
| 84 | + return self::$boolean_fields; |
| 85 | + } |
| 86 | + |
| 87 | + |
| 88 | + /** |
| 89 | + * getErrorToken, intended to be used by classes that exist relatively close |
| 90 | + * to the form classes, returns the error token (defined on the forms) that |
| 91 | + * specifies *where* the error will appear within the form output. |
| 92 | + * @param string $field The field that ostensibly has an error that needs to |
| 93 | + * be displayed to the user. |
| 94 | + * @return string The error token corresponding to a field, probably in |
| 95 | + * RapidHTML. |
| 96 | + */ |
| 97 | + public static function getErrorToken( $field ){ |
| 98 | + $error_token = 'general'; |
| 99 | + switch ( $field ) { |
| 100 | + case 'amountGiven' : |
| 101 | + case 'amountOther' : |
| 102 | + $error_token = 'amount'; |
| 103 | + break; |
| 104 | + case 'email' : |
| 105 | + $error_token = 'emailAdd'; |
| 106 | + break; |
| 107 | + case 'amount' : |
| 108 | + case 'card_num': |
| 109 | + case 'card_type': |
| 110 | + case 'cvv': |
| 111 | + case 'fname': |
| 112 | + case 'lname': |
| 113 | + case 'city': |
| 114 | + case 'country': |
| 115 | + case 'street': |
| 116 | + case 'state': |
| 117 | + case 'zip': |
| 118 | + $error_token = $field; |
| 119 | + break; |
| 120 | + } |
| 121 | + return $error_token; |
| 122 | + } |
| 123 | + |
| 124 | + |
| 125 | + /** |
| 126 | + * getErrorMessage - returns the translated error message appropriate for a |
| 127 | + * validation error on the specified field, of the specified type. |
| 128 | + * @param string $field - The common name of the field containing the data |
| 129 | + * that is causing the error. |
| 130 | + * @param type $type - The type of error being caused, from a set. |
| 131 | + * Possible values are: |
| 132 | + * 'non_empty' - the value is required and not currently present |
| 133 | + * 'valid_type' - in general, the wrong format |
| 134 | + * 'calculated' - fields that failed some kind of multiple-field data |
| 135 | + * integrity check. |
| 136 | + * @param string $value - The value of the field. So far, only used to say |
| 137 | + * more precise things about Credit Cards. |
| 138 | + */ |
| 139 | + public static function getErrorMessage( $field, $type, $value = null ){ |
| 140 | + //this is gonna get ugly up in here. |
| 141 | + error_log( __FUNCTION__ . " $field, $type, $value " ); |
| 142 | + |
| 143 | + //Empty messages should get: |
| 144 | + //'donate_interface-error-msg' => 'Please enter your $1'; |
| 145 | + //If they have no defined error message, give 'em the default. |
| 146 | + if ($type === 'non_empty'){ |
| 147 | + //NOTE: We are just using the next bit because it's convenient. |
| 148 | + //getErrorToken is actually for something entirely different: |
| 149 | + //Figuring out where on the form the error should land. |
| 150 | + $message_field = self::getErrorToken( $field ); |
| 151 | + if ( $field === 'expiration' ){ |
| 152 | + $message_field = $field; |
| 153 | + } |
| 154 | + //postal code is a weird one. More L10n than I18n. |
| 155 | + //'donate_interface-error-msg-postal' => 'postal code', |
| 156 | + |
| 157 | + $error_message_field_string = 'donate_interface-error-msg-' . $message_field; |
| 158 | + if ( $message_field != 'general' && self::wmfMessageExists( $error_message_field_string ) ) { |
| 159 | + return wfMsg( 'donate_interface-error-msg', wfMsg( $error_message_field_string ) ); |
| 160 | + } |
| 161 | + } |
| 162 | + |
| 163 | + if ( $type === 'valid_type' ) { |
| 164 | + //NOTE: We are just using the next bit because it's convenient. |
| 165 | + //getErrorToken is actually for something entirely different: |
| 166 | + //Figuring out where on the form the error should land. |
| 167 | + $token = self::getErrorToken( $field ); |
| 168 | + $suffix = $token; //defaultness |
| 169 | + switch ($token){ |
| 170 | + case 'amount': |
| 171 | + $suffix = 'invalid-amount'; |
| 172 | + case 'emailAdd': |
| 173 | + $suffix = 'email'; |
| 174 | + case 'card_num': //god damn it. |
| 175 | + $suffix = 'card_num'; //more defaultness. |
| 176 | + if (!is_null($value)){ |
| 177 | + $fake_suffix = self::getCardType($value); |
| 178 | + switch ( $fake_suffix ){ |
| 179 | + case 'american': |
| 180 | + $suffix = 'amex'; |
| 181 | + break; |
| 182 | + case 'mastercard': |
| 183 | + $suffix = 'mc'; |
| 184 | + break; |
| 185 | + case 'visa': |
| 186 | + case 'discover': |
| 187 | + $suffix = $fake_suffix; |
| 188 | + break; |
| 189 | + } |
| 190 | + } |
| 191 | + break; |
| 192 | + } |
| 193 | + |
| 194 | + $error_message_field_string = 'donate_interface-error-msg-' . $suffix; |
| 195 | + if ( self::wmfMessageExists( $error_message_field_string ) ) { |
| 196 | + return wfMsg( $error_message_field_string ); |
| 197 | + } |
| 198 | + } |
| 199 | + |
| 200 | + //ultimate defaultness. |
| 201 | + return wfMsg( 'donate_interface-error-msg-general' ); |
| 202 | + } |
| 203 | + |
| 204 | + |
| 205 | + /** |
| 206 | + * wmfMessageExists returns true if a translatable message has been defined |
| 207 | + * for the string that has been passed in, false if none is present. |
| 208 | + * TODO: See what this does in other languages when the string exists in |
| 209 | + * English, but not in the uselang. |
| 210 | + * @param string $msg_key The message string to look up. |
| 211 | + * @return boolean - true if message, exists, otherwise false. |
| 212 | + */ |
| 213 | + public static function wmfMessageExists( $msg_key ){ |
| 214 | + //we may have some problems here if this returns false positives if a |
| 215 | + //message exists in English, but not in the language we're looking for. |
| 216 | + //..but, they're not problems we don't already have. |
| 217 | + if ( wfEmptyMsg( $msg_key ) ) { |
| 218 | + return false; |
| 219 | + } else { |
| 220 | + return true; |
| 221 | + } |
| 222 | + } |
| 223 | + |
| 224 | + |
| 225 | + /** |
| 226 | + * validate |
| 227 | + * Run all the validation rules we have defined against a (hopefully |
| 228 | + * normalized) DonationInterface data set. |
| 229 | + * @param array $data The DonationInterface data set, or a subset thereof. |
| 230 | + * @param array $check_not_empty An array of fields to do empty validation |
| 231 | + * on. If this is not populated, no fields will throw errors for being empty, |
| 232 | + * UNLESS they are required for a field that uses them for more complex |
| 233 | + * validation (the 'calculated' phase). |
| 234 | + * @return array An array of errors in a format ready for any derivitive of |
| 235 | + * the main DonationInterface Form class to display. The array will be empty |
| 236 | + * if no errors were generated and everything passed OK. |
| 237 | + */ |
| 238 | + public static function validate( $data, $check_not_empty = array() ){ |
| 239 | + //return the array of errors that should be generated on validate. |
| 240 | + //just the same way you'd do it if you were a form passing the error array around. |
| 241 | + |
| 242 | + /** |
| 243 | + * We need to run the validation in an order that makes sense. |
| 244 | + * |
| 245 | + * First: If we need to validate that some things are not empty, do that. |
| 246 | + * Second: Do regular data type validation (on things that are not empty, |
| 247 | + * keeping in mind we may or may not have exploded on those yet. |
| 248 | + * Third: Do validation that depends on multiple fields (making sure you |
| 249 | + * validated that all the required fields exist on step 1, regardless of |
| 250 | + * $check_not_empty) |
| 251 | + * |
| 252 | + * So, we need to know what we're about to do for #3 before we actually do #1. |
| 253 | + * |
| 254 | + * $check_not_empty should contain an array of values that need to be populated. |
| 255 | + * One likely candidate for a source there, is the required stomp fields as defined in DonationData. |
| 256 | + * Although, a lot of those don't have to have any data in them either. Boo. |
| 257 | + * |
| 258 | + * How about we build an array of shit to do, |
| 259 | + * look at it to make sure it's complete, and in order... |
| 260 | + * ...and do it. |
| 261 | + */ |
| 262 | + |
| 263 | + $instructions = array( |
| 264 | + 'non_empty' => array(), |
| 265 | + 'valid_type' => array(), //simple 'valid_type' check functions only have one parameter. |
| 266 | + 'calculated' => array(), //'calculated' check functions depend on (or optionally have) more than one value. |
| 267 | + ); |
| 268 | + |
| 269 | + if ( !is_array( $check_not_empty ) ){ |
| 270 | + $check_not_empty = array( $check_not_empty ); |
| 271 | + } |
| 272 | + |
| 273 | + foreach ( $check_not_empty as $field ){ |
| 274 | + $instructions['non_empty'][$field] = 'validate_not_empty'; |
| 275 | + } |
| 276 | + |
| 277 | + foreach ( $data as $field => $value ){ |
| 278 | + //first, unset everything that's an empty string, or null, as there's nothing to validate. |
| 279 | + if ( $value !== '' && !is_null( $value ) ){ |
| 280 | + |
| 281 | + $function_name = self::getValidationFunction( $field ); |
| 282 | + $check_type = 'valid_type'; |
| 283 | + switch ( $function_name ) { |
| 284 | + case 'validate_amount': |
| 285 | + //Note: We could do something like also validate amount not empty, and then that it's numeric |
| 286 | + //That way we'd get more precisely granular error messages. |
| 287 | + $check_type = 'calculated'; |
| 288 | + $instructions['non_empty']['currency_code'] = 'validate_not_empty'; |
| 289 | + $instructions['valid_type']['currency_code'] = self::getValidationFunction( 'currency_code' ); |
| 290 | + $instructions['non_empty']['gateway'] = 'validate_not_empty'; |
| 291 | + $instructions['valid_type']['gateway'] = self::getValidationFunction( 'gateway' ); |
| 292 | + break; |
| 293 | + case 'validate_card_type': |
| 294 | + $check_type = 'calculated'; |
| 295 | + break; |
| 296 | + } |
| 297 | + $instructions[$check_type][$field] = $function_name; |
| 298 | + } |
| 299 | + } |
| 300 | + |
| 301 | + $errors = array(); |
| 302 | + |
| 303 | + $self = get_called_class(); |
| 304 | + |
| 305 | + foreach ( $instructions['non_empty'] as $field => $function ){ |
| 306 | + if ( method_exists( $self, $function ) && $function === 'validate_not_empty' ) { |
| 307 | + if ( $self::$function( $field, $data ) ){ |
| 308 | + $instructions['non_empty'][$field] = true; |
| 309 | + } else { |
| 310 | + $instructions['non_empty'][$field] = false; |
| 311 | + $errors[ self::getErrorToken( $field ) ] = self::getErrorMessage( $field, 'non_empty' ); |
| 312 | + } |
| 313 | + } else { |
| 314 | + $instructions['non_empty'][$field] === 'exception'; |
| 315 | + $errors[ self::getErrorToken( $field ) ] = self::getErrorMessage( $field, 'non_empty' ); |
| 316 | + throw new MWException( __FUNCTION__ . " BAD PROGRAMMER. No $function function. ('non_empty' rule for $field )" ); |
| 317 | + } |
| 318 | + } |
| 319 | + |
| 320 | + foreach ( $instructions['valid_type'] as $field => $function ){ |
| 321 | + if ( method_exists( $self, $function ) ) { |
| 322 | + if ( $self::$function( $data[$field] ) ){ |
| 323 | + $instructions['valid_type'][$field] = true; |
| 324 | + } else { |
| 325 | + $instructions['valid_type'][$field] = false; |
| 326 | + $errors[ self::getErrorToken( $field ) ] = self::getErrorMessage( $field, 'valid_type' ); |
| 327 | + } |
| 328 | + } else { |
| 329 | + $instructions['valid_type'][$field] === 'exception'; |
| 330 | + $errors[ self::getErrorToken( $field ) ] = self::getErrorMessage( $field, 'valid_type' ); |
| 331 | + throw new MWException( __FUNCTION__ . " BAD PROGRAMMER. No $function function. ('valid_type' rule for $field)" ); |
| 332 | + } |
| 333 | + } |
| 334 | + |
| 335 | + //don't bail out now. Just don't set errors for calculated fields that |
| 336 | + //have failures in their dependencies. |
| 337 | + foreach ( $instructions['calculated'] as $field => $function ){ |
| 338 | + if ( method_exists( $self, $function ) ) { |
| 339 | + //each of these is going to have its own set of overly |
| 340 | + //complicated rules and things to check, or we wouldn't be down |
| 341 | + //here in the calculated section. |
| 342 | + $result = null; |
| 343 | + switch ( $function ){ |
| 344 | + case 'validate_amount': |
| 345 | + if ( self::checkValidationPassed( array( 'currency_code', 'gateway' ), $instructions ) ){ |
| 346 | + $result = $self::$function( $data[$field], $data['currency_code'], $data['gateway'] ); |
| 347 | + } //otherwise, just don't do the validation. The other stuff will be complaining already. |
| 348 | + break; |
| 349 | + case 'validate_card_type': |
| 350 | + //the contingent field in this case isn't strictly required, so this is going to look funny. |
| 351 | + if ( array_key_exists( 'card_number', $instructions['valid_type'] ) && $instructions['valid_type']['card_number'] === true ){ |
| 352 | + //if it's there, it had better match up. |
| 353 | + $result = $self::$function( $data[$field], $data['card_number'] ); |
| 354 | + } else { |
| 355 | + $result = $self::$function( $data[$field] ); |
| 356 | + } |
| 357 | + break; |
| 358 | + } |
| 359 | + |
| 360 | + $instructions['calculated'][$field] = $result; |
| 361 | + if ($result === false){ //implying we did the check, and it failed. |
| 362 | + $errors[ self::getErrorToken( $field ) ] = self::getErrorMessage( $field, 'calculated' ); |
| 363 | + } |
| 364 | + |
| 365 | + } else { |
| 366 | + $instructions['calculated'][$field] === 'exception'; |
| 367 | + $errors[ self::getErrorToken( $field ) ] = self::getErrorMessage( $field, 'calculated' ); |
| 368 | + throw new MWException( __FUNCTION__ . " BAD PROGRAMMER. No $function function. ('calculated' rule for $field)" ); |
| 369 | + } |
| 370 | + } |
| 371 | + error_log( print_r( $errors, true ) ); |
| 372 | + return $errors; |
| 373 | + } |
| 374 | + |
| 375 | + |
| 376 | + /** |
| 377 | + * checkValidationPassed is a validate helper function. |
| 378 | + * In order to determine that we are ready to do the third stage of data |
| 379 | + * validation (calculated) for any given field, we need to determine that |
| 380 | + * all fields required to validate the original have, themselves, passed |
| 381 | + * validation. |
| 382 | + * @param array $fields An array of field names to check. |
| 383 | + * @param array $instruction_results The $instructions array used in the |
| 384 | + * validate function. |
| 385 | + * @return boolean true if all fields specified in $fields passed their |
| 386 | + * non_empty and valid_type validation. Otherwise, false. |
| 387 | + */ |
| 388 | + protected static function checkValidationPassed( $fields, $instruction_results ){ |
| 389 | + foreach ( $fields as $field ){ |
| 390 | + if ( !array_key_exists( $field, $instruction_results['non_empty'] ) || $instruction_results['non_empty'][$field] !== true ){ |
| 391 | + return false; |
| 392 | + } |
| 393 | + if ( !array_key_exists( $field, $instruction_results['valid_type'] ) || $instruction_results['valid_type'][$field] !== true ){ |
| 394 | + return false; |
| 395 | + } |
| 396 | + } |
| 397 | + return true; |
| 398 | + } |
| 399 | + |
| 400 | + |
| 401 | + /** |
| 402 | + * getValidationFunction returns the function to use to validate the given field. |
| 403 | + * @param string $field The name of the field we need to validate. |
| 404 | + */ |
| 405 | + static function getValidationFunction( $field ){ |
| 406 | + switch ( $field ){ |
| 407 | + case 'email': |
| 408 | + return 'validate_email'; |
| 409 | + break; |
| 410 | + case 'amount': //we only have to do the one: It will have been normalized by now. |
| 411 | + return 'validate_amount'; //this one is interesting. Needs two params. |
| 412 | + break; |
| 413 | + case 'card_num': |
| 414 | + return 'validate_credit_card'; |
| 415 | + break; |
| 416 | + case 'card_type': |
| 417 | + return 'validate_card_type'; |
| 418 | + break; |
| 419 | + case 'gateway': |
| 420 | + return 'validate_gateway'; |
| 421 | + break; |
| 422 | + } |
| 423 | + |
| 424 | + if ( in_array( $field, self::getNumericFields() ) ){ |
| 425 | + return 'validate_numeric'; |
| 426 | + } |
| 427 | + |
| 428 | + if ( in_array( $field, self::getBooleanFields() ) ){ |
| 429 | + return 'validate_boolean'; |
| 430 | + } |
| 431 | + |
| 432 | + return 'validate_alphanumeric'; //Yeah, this won't work. |
| 433 | + } |
| 434 | + |
| 435 | + |
| 436 | + /** |
| 437 | + * validate_email |
| 438 | + * Determines if the $value passed in is a valid email address. |
| 439 | + * @param string $value The piece of data that is supposed to be an email |
| 440 | + * address. |
| 441 | + * @return boolean True if $value is a valid email address, otherwise false. |
| 442 | + */ |
| 443 | + protected static function validate_email( $value ){ |
| 444 | + // is email address valid? |
| 445 | + $isEmail = User::isValidEmailAddr( $value ); |
| 446 | + return $isEmail; |
| 447 | + } |
| 448 | + |
| 449 | + |
| 450 | + /** |
| 451 | + * validate_amount |
| 452 | + * Determines if the $value passed in is a valid amount. |
| 453 | + * NOTE: You will need to make sure that currency_code is populated before |
| 454 | + * you get here. |
| 455 | + * @param string $value The piece of data that is supposed to be an amount. |
| 456 | + * @param string $currency_code Valid amounts depend on there being a |
| 457 | + * currency code also. This also needs to be passed in. |
| 458 | + * @param string $gateway The gateway needs to be provided so we can |
| 459 | + * determine that gateway's current price floor and ceiling. |
| 460 | + * @return boolean True if $value is a valid amount, otherwise false. |
| 461 | + */ |
| 462 | + protected static function validate_amount( $value, $currency_code, $gateway ){ |
| 463 | + if ( !$value || !$currency_code || !is_numeric( $value ) ) { |
| 464 | + return false; |
| 465 | + } |
| 466 | + |
| 467 | + // check amount |
| 468 | + $gateway_class = self::getGatewayClass($gateway); |
| 469 | + if ( !$gateway_class ){ |
| 470 | + return false; |
| 471 | + } |
| 472 | + |
| 473 | + $priceFloor = $gateway_class::getGlobal( 'PriceFloor' ); |
| 474 | + $priceCeiling = $gateway_class::getGlobal( 'PriceCeiling' ); |
| 475 | + if ( !preg_match( '/^\d+(\.(\d+)?)?$/', $value ) || |
| 476 | + ( ( float ) self::convert_to_usd( $currency_code, $value ) < ( float ) $priceFloor || |
| 477 | + ( float ) self::convert_to_usd( $currency_code, $value ) > ( float ) $priceCeiling ) ) { |
| 478 | + return false; |
| 479 | + } |
| 480 | + |
| 481 | + return true; |
| 482 | + } |
| 483 | + |
| 484 | + |
| 485 | + /** |
| 486 | + * validate_card_type |
| 487 | + * Determines if the $value passed in is (possibly) a valid credit card type. |
| 488 | + * @param string $value The piece of data that is supposed to be a credit card type. |
| 489 | + * @param string $card_number The card number associated with this card type. Optional. |
| 490 | + * @return boolean True if $value is a reasonable credit card type, otherwise false. |
| 491 | + */ |
| 492 | + protected static function validate_card_type( $value, $card_number = '' ) { |
| 493 | + if ( !array_key_exists( $value, self::$card_types ) ){ |
| 494 | + return false; |
| 495 | + } |
| 496 | + |
| 497 | + if ( $card_number != '' ){ |
| 498 | + $calculated_card_type = self::getCardType( $card_number ); |
| 499 | + if ( $calculated_card_type != $value ){ |
| 500 | + return false; |
| 501 | + } |
| 502 | + } |
| 503 | + |
| 504 | + return true; |
| 505 | + } |
| 506 | + |
| 507 | + |
| 508 | + /** |
| 509 | + * validate_credit_card |
| 510 | + * Determines if the $value passed in is (possibly) a valid credit card number. |
| 511 | + * @param string $value The piece of data that is supposed to be a credit card number. |
| 512 | + * @return boolean True if $value is a reasonable credit card number, otherwise false. |
| 513 | + */ |
| 514 | + protected static function validate_credit_card( $value ) { |
| 515 | + $calculated_card_type = self::getCardType( $value ); |
| 516 | + if ( !$calculated_card_type ){ |
| 517 | + return false; |
| 518 | + } |
| 519 | + |
| 520 | + return true; |
| 521 | + } |
| 522 | + |
| 523 | + |
| 524 | + /** |
| 525 | + * validate_boolean |
| 526 | + * Determines if the $value passed in is a valid boolean. |
| 527 | + * @param string $value The piece of data that is supposed to be a boolean. |
| 528 | + * @return boolean True if $value is a valid boolean, otherwise false. |
| 529 | + */ |
| 530 | + protected static function validate_boolean( $value ){ |
| 531 | + switch ($value) { |
| 532 | + case 0: |
| 533 | + case '0': |
| 534 | + case false: |
| 535 | + case 'false': |
| 536 | + case 1: |
| 537 | + case '1': |
| 538 | + case true: |
| 539 | + case 'true': |
| 540 | + return true; |
| 541 | + break; |
| 542 | + } |
| 543 | + return false; |
| 544 | + } |
| 545 | + |
| 546 | + |
| 547 | + /** |
| 548 | + * validate_numeric |
| 549 | + * Determines if the $value passed in is numeric. |
| 550 | + * @param string $value The piece of data that is supposed to be numeric. |
| 551 | + * @return boolean True if $value is numeric, otherwise false. |
| 552 | + */ |
| 553 | + protected static function validate_numeric( $value ){ |
| 554 | + //instead of validating here, we should probably be doing something else entirely. |
| 555 | + if ( is_numeric( $value ) ) { |
| 556 | + return true; |
| 557 | + } |
| 558 | + return false; |
| 559 | + } |
| 560 | + |
| 561 | + |
| 562 | + /** |
| 563 | + * validate_gateway |
| 564 | + * Checks to make sure the gateway is populated with a valid and enabled |
| 565 | + * gateway. |
| 566 | + * @param string $value The value that is meant to be a gateway. |
| 567 | + * @return boolean True if $value is a valid gateway, otherwise false |
| 568 | + */ |
| 569 | + protected static function validate_gateway( $value ){ |
| 570 | + if ( self::getGatewayClass( $value ) ){ |
| 571 | + return true; |
| 572 | + } |
| 573 | + |
| 574 | + return false; |
| 575 | + } |
| 576 | + |
| 577 | + |
| 578 | + /** |
| 579 | + * validate_not_empty |
| 580 | + * Checks to make sure that the $value is present in the $data array, and not null or an empty string. |
| 581 | + * Anything else that is 'falseish' is still perfectly valid to have as a data point. |
| 582 | + * TODO: Consider doing this in a batch. |
| 583 | + * @param string $value The value to check for non-emptyness. |
| 584 | + * @param array $data The whole data set. |
| 585 | + * @return boolean True if the $value is not missing or empty, otherwise false. |
| 586 | + */ |
| 587 | + protected static function validate_not_empty( $value, $data ){ |
| 588 | + error_log(__FUNCTION__ . ". Yup!"); |
| 589 | + if ( !array_key_exists( $value, $data ) || is_null( $data[$value] ) || $data[$value] === '' ){ |
| 590 | + return false; |
| 591 | + } |
| 592 | + return true; |
| 593 | + } |
| 594 | + |
| 595 | + /** |
| 596 | + * validate_alphanumeric |
| 597 | + * Checks to make sure the value is populated with an alphanumeric value... |
| 598 | + * ...which would be great, if it made sense at all. |
| 599 | + * TODO: This is duuuuumb. Make it do something good, or get rid of it. |
| 600 | + * If we can think of a way to make this useful, we should do something here. |
| 601 | + * @param string $value The value that is meant to be alphanumeric |
| 602 | + * @return boolean True if $value is ANYTHING. Or not. :[ |
| 603 | + */ |
| 604 | + protected static function validate_alphanumeric( $value ){ |
| 605 | + return true; |
| 606 | + } |
| 607 | + |
| 608 | + |
| 609 | + /** |
| 610 | + * getGatewayClass |
| 611 | + * This exists to enable things like logging to the correct gateway, and |
| 612 | + * retrieving gateway-specific globals. |
| 613 | + * @param string $gateway The gateway identifier. |
| 614 | + * @return string The name of the gateway class associated with that |
| 615 | + * identifier, or false if none exists. |
| 616 | + */ |
| 617 | + protected static function getGatewayClass( $gateway ) { |
| 618 | + if ( array_key_exists( $gateway, self::$gateway_classes ) && class_exists( self::$gateway_classes[$gateway] ) ){ |
| 619 | + return self::$gateway_classes[$gateway]; |
| 620 | + } |
| 621 | + return false; |
| 622 | + } |
| 623 | + |
| 624 | + |
| 625 | + /** |
| 626 | + * Convert an amount for a particular currency to an amount in USD |
| 627 | + * |
| 628 | + * This is grosley rudimentary and likely wildly inaccurate. |
| 629 | + * This mimicks the hard-coded values used by the WMF to convert currencies |
| 630 | + * for validatoin on the front-end on the first step landing pages of their |
| 631 | + * donation process - the idea being that we can get a close approximation |
| 632 | + * of converted currencies to ensure that contributors are not going above |
| 633 | + * or below the price ceiling/floor, even if they are using a non-US currency. |
| 634 | + * |
| 635 | + * In reality, this probably ought to use some sort of webservice to get real-time |
| 636 | + * conversion rates. |
| 637 | + * |
| 638 | + * @param string $currency_code |
| 639 | + * @param float $amount |
| 640 | + * @return float |
| 641 | + */ |
| 642 | + public static function convert_to_usd( $currency_code, $amount ) { |
| 643 | + require_once( dirname( __FILE__ ) . '/currencyRates.inc' ); |
| 644 | + $rates = getCurrencyRates(); |
| 645 | + $code = strtoupper( $currency_code ); |
| 646 | + if ( array_key_exists( $code, $rates ) ) { |
| 647 | + $usd_amount = $amount / $rates[$code]; |
| 648 | + } else { |
| 649 | + $usd_amount = $amount; |
| 650 | + } |
| 651 | + return $usd_amount; |
| 652 | + } |
| 653 | + |
| 654 | + |
| 655 | + /** |
| 656 | + * Calculates and returns the card type for a given credit card number. |
| 657 | + * @param numeric $card_num A credit card number. |
| 658 | + * @return mixed 'american', 'mastercard', 'visa', 'discover', or false. |
| 659 | + */ |
| 660 | + public static function getCardType( $card_num ) { |
| 661 | + // validate that credit card number entered is correct and set the card type |
| 662 | + if ( preg_match( '/^3[47][0-9]{13}$/', $card_num ) ) { // american express |
| 663 | + return 'american'; |
| 664 | + } elseif ( preg_match( '/^5[1-5][0-9]{14}$/', $card_num ) ) { // mastercard |
| 665 | + return 'mastercard'; |
| 666 | + } elseif ( preg_match( '/^4[0-9]{12}(?:[0-9]{3})?$/', $card_num ) ) {// visa |
| 667 | + return 'visa'; |
| 668 | + } elseif ( preg_match( '/^6(?:011|5[0-9]{2})[0-9]{12}$/', $card_num ) ) { // discover |
| 669 | + return 'discover'; |
| 670 | + } else { // an unrecognized card type was entered |
| 671 | + return false; |
| 672 | + } |
| 673 | + } |
| 674 | + |
| 675 | +} |
| 676 | + |
| 677 | +?> |
Property changes on: trunk/extensions/DonationInterface/gateway_common/DataValidator.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 678 | + native |