Getting array key value in nested arrays - php

I need to get an array value with the key name being "name" but I can’t seem to figure it out. I am displaying an error when a user doesn’t fill out a field and I want it to be more specific. In my case when I output an error the page says fname needs to be filled but in an array in my script that checks the required things in a form I listed a name and I want it to display First Name needs to be filled. My code is below.
<?php
require_once 'Assets/Scripts/Core/Init.php';
if(Input::exists()){
if(Token::check(Input::get('token'))){
$Validate = new Validate();
$Validation = $Validate->check($_POST, array(
'fname' => array(
'name' => 'First Name',
'required' => true,
'min' => '2',
'max' => '16',
'alpha' => true
),
'lname' => array(
'name' => 'Last Name',
'required' => true,
'min' => '2',
'max' => '16',
'alpha' => true
),
'email' => array(
'name' => 'E-Mail',
'required' => true,
'max' => '128',
'email' => true,
'unique' => 'users'
),
'password' => array(
'name' => 'Password',
'required' => true
),
'pn' => array(
'name' => 'Phone Number',
'required' => true,
'max' => '10',
'num' => true
),
'student_id' => array(
'name' => 'School ID',
'required' => true,
'max' => '10',
'num' => true
)
));
if($Validate->passed()){
$user = new User();
$salt = Hash::salt(32);
try {
$user->create('users', array(
'email' => Input::get('email'),
'password' => Hash::make(Input::get('password'), $salt),
'salt' => $salt,
'fname' => Input::get('fname'),
'lname' => Input::get('lname'),
'phone' => Input::get('pn'),
'student_id' => Input::get('student_id'),
'ip' => $_SERVER['REMOTE_ADDR'],
'date' => date('Y-m-d H:i:s'),
'usergroup' => 1
));
} catch(Exception $e) {
die($e->getMessage());
}
}
else {
echo print_r($Validate->errors());
}
}
}
My validation class:
<?php
class Validate {
private $_passed = false,
$_errors = array(),
$_db = null;
public function __construct(){
$this->_db = DB::getInstance();
}
public function check($data, $items = array()){
foreach($items as $item => $rules){
foreach($rules as $rule => $rule_value){
trim($value = $data[$item]);
$item = escape($item);
if($rule === 'required' && empty($value)){
$this->addError("{$item} is required");
}
else if(!empty($value)){
switch($rule){
case 'min':
if(strlen($value) < $rule_value){
$this->addError("{$item} must be a minimum of {$rule_value} characters.");
}
break;
case 'max':
if(strlen($value) > $rule_value){
$this->addError("{$item} must be a maximum of {$rule_value} characters.");
}
break;
case 'matches':
if($value != $data[$rule_value]){
$this->addError("{$rule_value} must match {$item}");
}
break;
case 'unique':
$check = $this->_db->get($rule_value, array($item, '=', $value));
if($check->count()){
$this->addError("{$item} already exists.");
}
break;
case 'email':
if(!filter_var($value, FILTER_VALIDATE_EMAIL)) {
$this->addError("{$item} is not a valid email.");
}
break;
case 'num':
if(!is_numeric($value)){
$this->addError("{$item} can only contain numbers.");
}
break;
case 'alpha':
if(!ctype_alpha($value))
{
$this->addError("{$item} can only contain letters.");
}
break;
}
}
}
}
if(empty($this->_errors)){
$this->_passed = true;
}
return $this;
}
private function addError($error){
$this->_errors[] = $error;
}
public function errors(){
return $this->_errors;
}
public function passed(){
return $this->_passed;
}
}
Input class:
<?php
class Input {
public static function exists($type = 'post'){
switch($type) {
case 'post':
return (!empty($_POST)) ? true : false;
break;
case 'get':
return (!empty($_POST)) ? true : false;
break;
default:
return false;
break;
}
}
public static function get($item){
if(isset($_POST[$item])){
return $_POST[$item];
}
elseif(isset($_GET[$item])){
return $_GET[$item];
}
else {
return '';
}
}
}
I need to be able to output the value that has the key 'name' in the fname array. In this case it should output First Name.

You need to move your "is required" section out of the rules loop so you can actually use it easily. Then you can also reference the "pretty" name easily.
Simply change your Validate::check function to:
public function check($data, $items = array()){
foreach($items as $item => $rules){
// check required earlier (moved to here)
if(isset($rules['required']) && $rules['required'] && empty($data[$item])) {
$this->addError($rules['name'] . " is required");
}
Please note that I changed it to use $rules['name'] instead of $item so you get the "pretty" name.
foreach($rules as $rule => $rule_value){
trim($value = $data[$item]);
$item = escape($item);
// removed the required check here
else if(!empty($value)){
switch($rule){
case 'min':
if(strlen($value) < $rule_value){
$this->addError("{$item} must be a minimum of {$rule_value} characters.");
}
break;
case 'max':
if(strlen($value) > $rule_value){
$this->addError("{$item} must be a maximum of {$rule_value} characters.");
}
break;
case 'matches':
if($value != $data[$rule_value]){
$this->addError("{$rule_value} must match {$item}");
}
break;
case 'unique':
$check = $this->_db->get($rule_value, array($item, '=', $value));
if($check->count()){
$this->addError("{$item} already exists.");
}
break;
case 'email':
if(!filter_var($value, FILTER_VALIDATE_EMAIL)) {
$this->addError("{$item} is not a valid email.");
}
break;
case 'num':
if(!is_numeric($value)){
$this->addError("{$item} can only contain numbers.");
}
break;
case 'alpha':
if(!ctype_alpha($value))
{
$this->addError("{$item} can only contain letters.");
}
break;
}
}
}
}
}

change $item to $rules['name']
public function check($data, $items = array()){
foreach($items as $item => $rules){
foreach($rules as $rule => $rule_value){
trim($value = $data[$item]);
$item = escape($item);
if($rule === 'required' && empty($value)){
$this->addError("{$rules['name']} is required");
}
else if(!empty($value)){
switch($rule){
case 'min':
if(strlen($value) < $rule_value){
$this->addError("{$item} must be a minimum of {$rule_value} characters.");
}
break;
case 'max':
if(strlen($value) > $rule_value){
$this->addError("{$item} must be a maximum of {$rule_value} characters.");
}
break;
case 'matches':
if($value != $data[$rule_value]){
$this->addError("{$rule_value} must match {$item}");
}
break;
case 'unique':
$check = $this->_db->get($rule_value, array($item, '=', $value));
if($check->count()){
$this->addError("{$item} already exists.");
}
break;
case 'email':
if(!filter_var($value, FILTER_VALIDATE_EMAIL)) {
$this->addError("{$item} is not a valid email.");
}
break;
case 'num':
if(!is_numeric($value)){
$this->addError("{$item} can only contain numbers.");
}
break;
case 'alpha':
if(!ctype_alpha($value))
{
$this->addError("{$item} can only contain letters.");
}
break;
}
}
}
}

Related

PHP search array column for 2 values using in_array()

How do I search for 2 values in the same record using in_array()?
For example I want to search for 'AuthorNiceName' value and 'AuthorType' value.
The below code does not work how I would like. It should return "EU TEST" but it returns "CP TEST".
Thanks in advance.
$authors = array(
array(
'AuthorName' => 'John Smith',
'AuthorNiceName' => 'john-smith',
'AuthorType' => 'CP'
),
array(
'AuthorName' => 'Joe Bloggs',
'AuthorNiceName' => 'joe-bloggs',
'AuthorType' => 'EU'
),
);
if (in_array('joe-bloggs', array_column($authors, 'AuthorNiceName')) && in_array('EU', array_column($authors, 'AuthorType'))) {
$authorType = 'CP TEST';
}
else {
$authorType = 'EU TEST';
}
echo $authorType;
UPDATE: My latest code using #Philipp's suggestion which I adjusted slightly. However it doesn't work, if there are other users with the same 'AuthorType' it returns "no match"?
$authors = array( //TODO
array(
'AuthorName' => 'John Smith',
'AuthorNiceName' => 'john-smith',
'AuthorType' => 'CP'
),
array(
'AuthorName' => 'Joe Bloggs',
'AuthorNiceName' => 'joe-bloggs',
'AuthorType' => 'EU'
),
array(
'AuthorName' => 'Matt Bat',
'AuthorNiceName' => 'matt-bat',
'AuthorType' => 'EU'
),
);
$name = 'joe-bloggs';
$type = 'EU';
foreach ($authors as $author) {
if ($author['AuthorNiceName'] == $name && $author['AuthorType'] == 'EU') {
$authorType = 'EU Test';
}
elseif ($author['AuthorNiceName'] == $name && $author['AuthorType'] == 'CP') {
$authorType = 'CP Test';
}
else {
$authorType = 'no match';
}
}
echo $authorType; //returns "not match". it should return "EU Test".
It seems, you should use a loop for what you want
$name = 'joe-bloggs';
$type = 'EU';
foreach ($authors as $author) {
if ($author['AuthorNiceName'] == $name && $author['AuthorType'] == $type) {
// do something
}
}
using in_array with array_column looses the information if the result is from the same column. Using array_search, you could also compare the index of the columns, but this seems like a bad solution...
Update
The problem with your update is, you overwrite the $authorType var, after you set the correct value. You should check, if an value is already set and only then set a new value.
$name = 'joe-bloggs';
$authorType = false;
foreach ($authors as $author) {
if ($author['AuthorNiceName'] == $name && $author['AuthorType'] == 'EU') {
$authorType = 'EU Test';
} elseif ($author['AuthorNiceName'] == $name && $author['AuthorType'] == 'CP') {
$authorType = 'CP Test';
}
}
if ($authorType === false) {
echo 'no match';
} else {
echo $authorType;
}

PHP multidimensional array repetitive output

The following code cycles through an array of requirements for user submitted data (in this case from a registration form) and outputs repetitive error messages. How to stop the repetitive messages?
if(!empty($_POST)){
$validate = array(
'username' => array(
'required' => true,
'min' => 3,
'max' => 20,
'unique' => 'users'
),
'password' => array(
'required' => true,
'min' => 6
),
'password_confirm' => array(
'required' => true,
'matches' => 'password'
)
);
foreach($validate as $item => $rules)
{
foreach($rules as $rule => $rule_value)
{
$value = $_POST[$item];
$item = htmlentities($item, ENT_QUOTES, 'UTF-8', false);
if($rule === 'required' && empty($value))
{
$errors[] = "{$item} is required <br>";
}
}
if(!empty($errors))
{
foreach($errors as $error)
{
echo $error;
}
}
else
{
echo 'Registration Successful <br>';
}
}}
Output:
username is required
username is required
password is required
username is required
password is required
password_confirm is required
Your loops have gotten a bit mixed up.
foreach($validate as $item => $rules)
{
foreach($rules as $rule => $rule_value)
{
$value = $_POST[$item];
$item = htmlentities($item, ENT_QUOTES, 'UTF-8', false);
if($rule === 'required' && empty($value))
{
$errors[] = "{$item} is required <br>";
}
}
}
// This piece that prints out the errors (if they are present) needs
// to be moved outside the loop that creates the error array.
if(!empty($errors))
{
foreach($errors as $error)
{
echo $error;
}
}
else
{
echo 'Registration Successful <br>';
}
Also, maybe you simplified this code for the purpose of asking the question, but if this is all there is to it, why not just print the error at the time you find it instead of appending it to an array of errors? That way you only have to loop once. You can just use a boolean to see if there were errors.
$has_errors = false;
foreach($validate as $item => $rules)
{
foreach($rules as $rule => $rule_value)
{
$value = $_POST[$item];
$item = htmlentities($item, ENT_QUOTES, 'UTF-8', false);
if($rule === 'required' && empty($value))
{
$has_errors = true;
echo "{$item} is required <br>";
}
}
}
if (!$has_errors) echo 'Registration Successful <br>';

Styling a variable data without undeclared variable error

I have an error and that is happening because I'm changing the $item name cause I want it to be uppercase. I've already done it for most of my code but for some reason I'm having some trouble doing so in here.
Here is the code:
public function check($source, $items = array()) {
foreach($items as $item => $rules) {
foreach($rules as $rule => $rule_value) {
$value = $source[$item];
$item = escape($item);
if ($rule === 'required' && empty($value)) {
$error = str_replace(array('_'), ' ', $item);
$this->addError(ucfirst($error) . " is required");
} else if(!empty($value)){
switch($rule) {
case 'min':
if(strlen($value) < $rule_value) {
$this->addError(ucfirst($item) . " must be a minimum of {$rule_value} characters.");
}
break;
case 'max':
if(strlen($value) > $rule_value) {
$this->addError(ucfirst($item) . " must be a maximum of {$rule_value} characters.");
}
break;
case 'matches':
if($value != $source[$rule_value]) {
$item = str_replace(array('_'), ' ', $item);
$this->addError(ucfirst($item) . ' does not match ' . $rule_value);
}
break;
case 'unique':
$check = $this->_db->get('*', $rule_value, array($item, '=', $value));
if ($check->count()){
$this->addError(ucfirst($item) . ' is already in use!');
}
break;
}
}
}
}
if(empty($this->_errors)) {
$this->_passed = true;
}
return $this;
}
Problematic code is:
if ($rule === 'required' && empty($value)) {
$item = str_replace(array('_'), ' ', $item);
$this->addError(ucfirst($item) . " is required");
}
I'm trying to make it so it outputs Password again is required instead of password_again is required. Everything in the switch($rule) statement is working properly but like I said I don't know why it doesn't work at that specific line. Anyone got an idea?
Exact Error: Notice: Undefined index: password confirm in C:\xampp\htdocs\classes\Validate.php on line 13.
What I thought of:
Suppression of the notice. This is good but I would really love it if this can be fixed.
Code Request [Source & Item]:
$validation = $validate->check($_POST, array(
'email' => array(
'required' => true,
'min' => 7,
'max' => 64,
'unique' => 'users'
),
'password' => array(
'required' => true,
'min' => 7,
'max' => 32
),
'password_confirm' => array(
'required' => true,
'matches' => 'password'
)
));
Var Dump Result:
string(5) "email"
Notice: Undefined property: Validate::$addError in C:\xampp\htdocs\classes\Validate.php on line 18
NULL string(8) "password"
Notice: Undefined property: Validate::$addError in C:\xampp\htdocs\classes\Validate.php on line 18
NULL string(16) "password confirm"
Notice: Undefined property: Validate::$addError in C:\xampp\htdocs\classes\Validate.php on line 18
NULL
Notice: Undefined index: password confirm in C:\xampp\htdocs\classes\Validate.php on line 13
New Working Code:
if ($rule === 'required' && empty($value)) {
$error = str_replace(array('_'), ' ', $item);
$this->addError(ucfirst($error) . " is required");
}
You're missing an empty check which is why the notice gets displayed when email, password or password_confirm is missing:
if( !empty( $source[$item] ) )
{
$value = $source[$item];
$item = escape($item);
if ($rule === 'required' && empty($value)) {
$item = str_replace(array('_'), ' ', $item);
$this->addError(ucfirst($item) . " is required");
} else if(!empty($value)){
switch($rule) {
case 'min':
if(strlen($value) < $rule_value) {
$this->addError(ucfirst($item) . " must be a minimum of {$rule_value} characters.");
}
break;
case 'max':
if(strlen($value) > $rule_value) {
$this->addError(ucfirst($item) . " must be a maximum of {$rule_value} characters.");
}
break;
case 'matches':
if($value != $source[$rule_value]) {
$item = str_replace(array('_'), ' ', $item);
$this->addError(ucfirst($item) . ' does not match ' . $rule_value);
}
break;
case 'unique':
// $check = $this->_db->get('*', $rule_value, array($item, '=', $value));
if ( 1 == 1 ){
$this->addError(ucfirst($item) . ' is already in use!');
}
break;
}
}
}
else
{
$this->addError( $item . ' cannot be empty!' );
break;
}
I would recommend a simpler solution.
Full replication as requested:
function escape( $sValue )
{
return trim( $sValue );
}
class test
{
public $aErrors = array();
public function addError( $sError )
{
$this->aErrors[] = $sError;
}
public function check($source, $items = array()) {
foreach($items as $item => $rules) {
foreach($rules as $rule => $rule_value) {
if( !empty( $source[$item] ) )
{
$value = $source[$item];
$item = escape($item);
if ($rule === 'required' && empty($value)) {
$item = str_replace(array('_'), ' ', $item);
$this->addError(ucfirst($item) . " is required");
} else if(!empty($value)){
switch($rule) {
case 'min':
if(strlen($value) < $rule_value) {
$this->addError(ucfirst($item) . " must be a minimum of {$rule_value} characters.");
}
break;
case 'max':
if(strlen($value) > $rule_value) {
$this->addError(ucfirst($item) . " must be a maximum of {$rule_value} characters.");
}
break;
case 'matches':
if($value != $source[$rule_value]) {
$item = str_replace(array('_'), ' ', $item);
$this->addError(ucfirst($item) . ' does not match ' . $rule_value);
}
break;
case 'unique':
// $check = $this->_db->get('*', $rule_value, array($item, '=', $value));
if ( 1 == 1 ){
$this->addError(ucfirst($item) . ' is already in use!');
}
break;
}
}
}
else
{
$this->addError( $item . ' cannot be empty!' );
break;
}
}
}
}
}
$_POST[ 'email' ] = '';
$_POST[ 'password' ] = '';
$_POST[ 'password_confirm' ] = '';
$aValidation = $cTest->check( $_POST,
array( 'email' => array( 'required' => true, 'min' => 7, 'max' => 64, 'unique' => 'users' ),
'password' => array( 'required' => true, 'min' => 7, 'max' => 32 ),
'password_confirm' => array( 'required' => true, 'matches' => 'password' ) ));
var_dump( $cTest->aErrors );
var_dump( $aValidation );

Comparing two arrays in PHP foreach

What's the best way to compare both two arrays to each other in a foreach loop ?
I have two arrays, which one holds a boolean values and other one represents the real values.
First one of the arrays is some sort of configuration file where I tell what field is a required one TRUE or an optional FALSE:
$rules = array(
'fieldname1' => TRUE,
'fieldname2' => FALSE,
'fieldname3' => TRUE,
'fieldname4' => TRUE,
'fieldname5' => FALSE,
'fieldname6' => FALSE,
'fieldname7' => TRUE,
'fieldname8' => TRUE
);
And the other array which holds incoming data to be worked out:
$fields = array(
'fieldname1' => 'some value',
'fieldname3' => 'some value',
'fieldname4' => 'some value',
'fieldname7' => 'some value',
'fieldname8' => 'some value'
);
How do I make a check in foreach() loop, so the $fields array is going to compare each of its fieldnameX or (keys/indexes) with the other array named $rules ?
For example: $rules['fieldname1'] is required as it have a bool TRUE. So in foreach($fields as $field), the $field named fieldname1 should not be empty, null or false, if so, show an error.
This is a function I did so far which is not doing exactly what I want:
private function check_field_required_exist( $fields )
{
// Read rules from config to work with them accordingly
$rules = config_item('flow.format')[$fields['format']];
// Run throught the rules
foreach( array_keys($rules) as $field )
{
// Check wheter key existance is failed
if( !array_key_exists($field, $fields) )
{
// Checking failed, terminate the process
die('Required field: "'. $field .'" for requested format: "'.$fields['format'].'" does not exists.');
}
}
// Everything is alright
return TRUE;
}
// Goes through all the rules
foreach($rules as $key => $value)
{
// access all fields that are marked as required i.e key set as TRUE
if ($value)
{
//for those whose value is TRUE, check whether the corresponding field is set or
// whether it is empty (NULL,false)
if(!isset($fields[$key]) || empty($fields[$key]))
{
die('Required field does not exist');
}
}
}
foreach ($fields as $field => $value)
{
if (array_key_exists($field, $rules) && $rules[$field] === true)
{
if (!$value || $value == "" || $value === null)
{
die(); // return false;
}
}
}
return true;
I think that you can play around with the array functions in PHP. First thing I would do is to apply array_filter on your rules array. That way, you will only keep the TRUE values (and their indexes, since array_filter keep the index/value association).
Then I would use array_intersect_key to keep only the fields of interest in your fields var. And again array_filter with a custom callback to perform the verification you want to do.
$requiredField = array();
foreach($rules as $key=>$value) {
if($value == true && (!isset($fields[$key]) || $fields[$key] == "" )) {
$requiredField[] = $key;
}
}
if(count($requiredField) > 0) {
echo implode(',',$requiredField)." Are Required";
die;
}
USING PHP Array Functions:
$rules = array('name' => TRUE, 'phoneNumber' => TRUE, 'age' => FALSE);
$submittedFields = array( 'name' => 'aspirinemaga', 'age' => 38, 'phoneNumber' => '');
$requiredFields = array_keys(array_filter($rules));
$validFields = array_keys(array_filter($submittedFields));
$missingFields = array_diff($requiredFields, $validFields);
Given
$rules = array('name' => TRUE, 'phoneNumber' => TRUE, 'age' => FALSE);
$submittedFields = array( 'name' => 'aspirinemaga', 'age' => 38, 'phoneNumber' => '');
PhoneNumber is wrong here.
$requiredFields = array_keys(array_filter($rules));
This gives you the keys of all rule elements that are TRUE.
$validFields = array_keys(array_filter($submittedFields));
Same here, your definition of what's ok is the same as php truth table for boolean conversion. If you have a more advanced check, you could pass a function name into array_filter (see below).
$missingFields = array_diff($requiredFields, $validFields);
This will get you all the fieldNames that exist in $requiredFields but are not in $validFields.
More advanced validation
$rules = array('name' => 'MORE_THAN_3', 'phoneNumber' => TRUE, 'age' => 'POSITIVE');
$submittedFields = array( 'name' => 'aspirinemaga', 'age' => 38, 'phoneNumber' => '');
$requiredFields = array_keys(array_filter($rules));
function validateField($key, $value){
// get the rule (assuming no submittedFields that have no rule)
$rule = $rules[$key];
switch($rule){
case 'MORE_THAN_3': return strlen($value) > 3; break;
case 'POSITIVE': return $value > 0; break;
}
// in case of TRUE/FALSE
return TRUE;
}
$validFields = array_keys(array_filter("validateField", $submittedFields, ARRAY_FILTER_USE_BOTH));
$missingFields = array_diff($requiredFields, $validFields);
If you wanted to do a more advanced validation, you can integrate that nicely into above solution.
Say you wanted name to be more than 3 characters and age to be positive. Write it into your rules:
$rules = array('name' => 'MORE_THAN_3', 'phoneNumber' => TRUE, 'age' => 'POSITIVE');
$submittedFields = array( 'name' => 'aspirinemaga', 'age' => 38, 'phoneNumber' => '');
Required Fields are still the same (to check if one is missing).
$requiredFields = array_keys(array_filter($rules));
Now your validate function would be something like:
function validateField($key, $value){
// get the rule (assuming no submittedFields that have no rule)
$rule = $rules[$key];
switch($rule){
case 'MORE_THAN_3': return strlen($value) > 3; break;
case 'POSITIVE': return $value > 0; break;
}
// in case of TRUE/FALSE
return TRUE;
}
Pass that into array_filter and add to ARRAY_FILTER_USE_BOTH Flag:
$validFields = array_keys(array_filter("validateField", $submittedFields, ARRAY_FILTER_USE_BOTH));
And your missing Fields stays the same.
$missingFields = array_diff($requiredFields, $validFields);
This will only work in PHP 5.6+ (because ARRAY_FILTER_USE_BOTH). Not tested, should work.

I have a php validator and it returns true, but I need to add the false

I need help with this code, is a credit card validation, I been trying to make it work in my code but I can't, I just need to obtain 2 variables, is the card is working it should return true that works, but if not it shows an error message, but I also need to obtain a return false, here is the code:
<?php
$cardnumber = $_POST['CardNumber'];
$cardname = $_POST['CardType'];
$cards = array ( array ('name' => 'American Express',
'length' => '15',
'prefixes' => '34,37',
'checkdigit' => true
),
array ('name' => 'Diners Club Carte Blanche',
'length' => '14',
'prefixes' => '300,301,302,303,304,305',
'checkdigit' => true
),
array ('name' => 'Diners Club',
'length' => '14,16',
'prefixes' => '36,38,54,55',
'checkdigit' => true
),
array ('name' => 'Discover',
'length' => '16',
'prefixes' => '6011,622,64,65',
'checkdigit' => true
),
array ('name' => 'Diners Club Enroute',
'length' => '15',
'prefixes' => '2014,2149',
'checkdigit' => true
),
array ('name' => 'JCB',
'length' => '16',
'prefixes' => '35',
'checkdigit' => true
),
array ('name' => 'Maestro',
'length' => '12,13,14,15,16,18,19',
'prefixes' => '5018,5020,5038,6304,6759,6761,6762,6763',
'checkdigit' => true
),
array ('name' => 'MasterCard',
'length' => '16',
'prefixes' => '51,52,53,54,55',
'checkdigit' => true
),
array ('name' => 'Solo',
'length' => '16,18,19',
'prefixes' => '6334,6767',
'checkdigit' => true
),
array ('name' => 'Switch',
'length' => '16,18,19',
'prefixes' => '4903,4905,4911,4936,564182,633110,6333,6759',
'checkdigit' => true
),
array ('name' => 'VISA',
'length' => '16',
'prefixes' => '4',
'checkdigit' => true
),
array ('name' => 'VISA Electron',
'length' => '16',
'prefixes' => '417500,4917,4913,4508,4844',
'checkdigit' => true
),
array ('name' => 'LaserCard',
'length' => '16,17,18,19',
'prefixes' => '6304,6706,6771,6709',
'checkdigit' => true
)
);
$ccErrorNo = 0;
$ccErrors [0] = "Unknown card type";
$ccErrors [1] = "No card number provided";
$ccErrors [2] = "Credit card number has invalid format";
$ccErrors [3] = "Credit card number is invalid";
$ccErrors [4] = "Credit card number is wrong length";
// Establish card type
$cardType = -1;
for ($i=0; $i<sizeof($cards); $i++) {
// See if it is this card (ignoring the case of the string)
if (strtolower($cardname) == strtolower($cards[$i]['name'])) {
$cardType = $i;
break;
}
}
// If card type not found, report an error
if ($cardType == -1) {
$errornumber = 0;
$errortext = $ccErrors [$errornumber];
return true;
}
// Ensure that the user has provided a credit card number
if (strlen($cardnumber) == 0) {
$errornumber = 1;
$errortext = $ccErrors [$errornumber];
return true;
}
// Remove any spaces from the credit card number
$cardNo = str_replace (' ', '', $cardnumber);
// Check that the number is numeric and of the right sort of length.
if (!preg_match("/^[0-9]{13,19}$/",$cardNo)) {
$errornumber = 2;
$errortext = $ccErrors [$errornumber];
return true;
}
// Now check the modulus 10 check digit - if required
if ($cards[$cardType]['checkdigit']) {
$checksum = 0; // running checksum total
$mychar = ""; // next char to process
$j = 1; // takes value of 1 or 2
// Process each digit one by one starting at the right
for ($i = strlen($cardNo) - 1; $i >= 0; $i--) {
// Extract the next digit and multiply by 1 or 2 on alternative digits.
$calc = $cardNo{$i} * $j;
// If the result is in two digits add 1 to the checksum total
if ($calc > 9) {
$checksum = $checksum + 1;
$calc = $calc - 10;
}
// Add the units element to the checksum total
$checksum = $checksum + $calc;
// Switch the value of j
if ($j ==1) {$j = 2;} else {$j = 1;};
}
// All done - if checksum is divisible by 10, it is a valid modulus 10.
// If not, report an error.
if ($checksum % 10 != 0) {
$errornumber = 3;
$errortext = $ccErrors [$errornumber];
return true;
}
}
// The following are the card-specific checks we undertake.
// Load an array with the valid prefixes for this card
$prefix = explode(',',$cards[$cardType]['prefixes']);
// Now see if any of them match what we have in the card number
$PrefixValid = false;
for ($i=0; $i<sizeof($prefix); $i++) {
$exp = '/^' . $prefix[$i] . '/';
if (preg_match($exp,$cardNo)) {
$PrefixValid = true;
break;
}
}
// If it isn't a valid prefix there's no point at looking at the length
if (!$PrefixValid) {
$errornumber = 3;
$errortext = $ccErrors [$errornumber];
return true;
}
// See if the length is valid for this card
$LengthValid = false;
$lengths = explode(',',$cards[$cardType]['length']);
for ($j=0; $j<sizeof($lengths); $j++) {
if (strlen($cardNo) == $lengths[$j]) {
$LengthValid = true;
break;
}
}
// See if all is OK by seeing if the length was valid.
if (!$LengthValid) {
$errornumber = 4;
$errortext = $ccErrors [$errornumber];
return true;
};
// The credit card is in the required format.
return true;
echo $errortext;
?>
you can see there is return true, but I also need to change this to false when the card is not validated so I can make other validation, thanks for any help.
I find other code that do what I need, is a little more simple, is possible to add the $verified variable of this new code to the first one? here is the code:
<?php
$cc_number = $_POST['CardNumber'];
$type = $_POST['CardType'];
$cc_num = str_replace (' ', '', $cc_number);
if($type == "AX") {
$denum = "American Express";
} elseif($type == "DC") {
$denum = "Diner's Club";
} elseif($type == "DS") {
$denum = "Discover";
} elseif($type == "MC") {
$denum = "Master Card";
} elseif($type == "VI") {
$denum = "Visa";
}
if($type == "AX") {
$pattern = "/^([34|37]{2})([0-9]{13})$/";//American Express
if (preg_match($pattern,$cc_num)) {
$verified = true;
} else {
$verified = false;
}
} elseif($type == "DC") {
$pattern = "/^([30|36|38]{2})([0-9]{12})$/";//Diner's Club
if (preg_match($pattern,$cc_num)) {
$verified = true;
} else {
$verified = false;
}
} elseif($type == "DS") {
$pattern = "/^([6011]{4})([0-9]{12})$/";//Discover Card
if (preg_match($pattern,$cc_num)) {
$verified = true;
} else {
$verified = false;
}
} elseif($type == "MC") {
$pattern = "/^([51|52|53|54|55]{2})([0-9]{14})$/";//Mastercard
if (preg_match($pattern,$cc_num)) {
$verified = true;
} else {
$verified = false;
}
} elseif($type == "VI") {
$pattern = "/^([4]{1})([0-9]{12,15})$/";//Visa
if (preg_match($pattern,$cc_num)) {
$verified = true;
} else {
$verified = false;
}
}
if($verified == false) {
//Do something here in case the validation fails
echo "Credit card invalid. Please make sure that you entered a valid <em>" . $denum . "</em> credit card ";
} else { //if it will pass...do something
echo "Your <em>" . $denum . "</em> credit card is valid";
}
?>
Declare a variable at the top of your function:
$invalid = false;
Then everywhere in your code where you have return true; change it to: $invalid = true;.
Then you can just do return $invalid; at the end of your function. It will return true if there was an error. If there is no error it will return false.
Look at all the if statements that look like this:
$errornumber = whateverNumber;
$errortext = $ccErrors [$errornumber];
return true;
Those are what return true when there is an error. Simply change the return statement to return false; in those places to make the script return false.
The only return true; should be at the end of your function.
thanks for help, here is the final code, I just make some changes and works great:
$cards = array ( array ('name' => 'American Express',
'length' => '15',
'prefixes' => '34,37',
'checkdigit' => true
),
array ('name' => 'Diners Club Carte Blanche',
'length' => '14',
'prefixes' => '300,301,302,303,304,305',
'checkdigit' => true
),
array ('name' => 'Diners Club',
'length' => '14,16',
'prefixes' => '36,38,54,55',
'checkdigit' => true
),
array ('name' => 'Discover',
'length' => '16',
'prefixes' => '6011,622,64,65',
'checkdigit' => true
),
array ('name' => 'Diners Club Enroute',
'length' => '15',
'prefixes' => '2014,2149',
'checkdigit' => true
),
array ('name' => 'JCB',
'length' => '16',
'prefixes' => '35',
'checkdigit' => true
),
array ('name' => 'Maestro',
'length' => '12,13,14,15,16,18,19',
'prefixes' => '5018,5020,5038,6304,6759,6761,6762,6763',
'checkdigit' => true
),
array ('name' => 'MasterCard',
'length' => '16',
'prefixes' => '51,52,53,54,55',
'checkdigit' => true
),
array ('name' => 'Solo',
'length' => '16,18,19',
'prefixes' => '6334,6767',
'checkdigit' => true
),
array ('name' => 'Switch',
'length' => '16,18,19',
'prefixes' => '4903,4905,4911,4936,564182,633110,6333,6759',
'checkdigit' => true
),
array ('name' => 'VISA',
'length' => '16',
'prefixes' => '4',
'checkdigit' => true
),
array ('name' => 'VISA Electron',
'length' => '16',
'prefixes' => '417500,4917,4913,4508,4844',
'checkdigit' => true
),
array ('name' => 'LaserCard',
'length' => '16,17,18,19',
'prefixes' => '6304,6706,6771,6709',
'checkdigit' => true
)
);
$ccErrorNo = 0;
$ccErrors [0] = "Unknown card type";
$ccErrors [1] = "No card number provided";
$ccErrors [2] = "Credit card number has invalid format";
$ccErrors [3] = "Credit card number is invalid";
$ccErrors [4] = "Credit card number is wrong length";
// Establish card type
$cardType = -1;
for ($i=0; $i<sizeof($cards); $i++) {
// See if it is this card (ignoring the case of the string)
if (strtolower($cardname) == strtolower($cards[$i]['name'])) {
$cardType = $i;
$response = true;
break;
}
}
// If card type not found, report an error
if ($cardType == -1) {
$errornumber = 0;
$errortext = $ccErrors [$errornumber];
$response = false;
return false;
}
// Ensure that the user has provided a credit card number
if (strlen($cardnumber) == 0) {
$errornumber = 1;
$errortext = $ccErrors [$errornumber];
$response = false;
return false;
}
// Remove any spaces from the credit card number
$cardNo = str_replace (' ', '', $cardnumber);
// Check that the number is numeric and of the right sort of length.
if (!preg_match("/^[0-9]{13,19}$/",$cardNo)) {
$errornumber = 2;
$errortext = $ccErrors [$errornumber];
$response = false;
return false;
}
// Now check the modulus 10 check digit - if required
if ($cards[$cardType]['checkdigit']) {
$checksum = 0; // running checksum total
$mychar = ""; // next char to process
$j = 1; // takes value of 1 or 2
// Process each digit one by one starting at the right
for ($i = strlen($cardNo) - 1; $i >= 0; $i--) {
// Extract the next digit and multiply by 1 or 2 on alternative digits.
$calc = $cardNo{$i} * $j;
// If the result is in two digits add 1 to the checksum total
if ($calc > 9) {
$checksum = $checksum + 1;
$calc = $calc - 10;
}
// Add the units element to the checksum total
$checksum = $checksum + $calc;
// Switch the value of j
if ($j ==1) {$j = 2;} else {$j = 1;};
}
// All done - if checksum is divisible by 10, it is a valid modulus 10.
// If not, report an error.
if ($checksum % 10 != 0) {
$errornumber = 3;
$errortext = $ccErrors [$errornumber];
$response = false;
return false;
}
}
// The following are the card-specific checks we undertake.
// Load an array with the valid prefixes for this card
$prefix = explode(',',$cards[$cardType]['prefixes']);
// Now see if any of them match what we have in the card number
$PrefixValid = false;
for ($i=0; $i<sizeof($prefix); $i++) {
$exp = '/^' . $prefix[$i] . '/';
if (preg_match($exp,$cardNo)) {
$PrefixValid = true;
$response = true;
break;
}
}
// If it isn't a valid prefix there's no point at looking at the length
if (!$PrefixValid) {
$errornumber = 3;
$errortext = $ccErrors [$errornumber];
$response = false;
return false;
}
// See if the length is valid for this card
$LengthValid = false;
$lengths = explode(',',$cards[$cardType]['length']);
for ($j=0; $j<sizeof($lengths); $j++) {
if (strlen($cardNo) == $lengths[$j]) {
$LengthValid = true;
$response = true;
break;
}
}
// See if all is OK by seeing if the length was valid.
if (!$LengthValid) {
$errornumber = 4;
$errortext = $ccErrors [$errornumber];
$response = false;
return false;
};
// The credit card is in the required format.
return $response;
in the other page:
$cardnumber = $_POST['CardNumber'];
$cardname = $_POST['CardType'];
require('phpcreditcard.php');
if ($response == true) {
echo 'works';
}
elseif ($response == false) {
echo $errortext;
}

Categories