Import CSV Validation in PHP - php

I am trying to upload/import CSV into SQL server with some basic validation such as CSV headers should contain 'SecurityID' and 'SecurityID' value can NOT be NULL and has NUMERIC value. I'm having some issue validating headers part and stuck. Below is my code from functions.php. For clarity I've removed DB insert/update code as I am not getting that far.
if(isset($_POST["Import"])){
$filetempname=$_FILES['file']['tmp_name'];
$filename=$_FILES['file']['name'];
$filetype = $_FILES['file']['type'];
$csv_mimetypes = array(
'text/csv',
'text/plain',
'application/csv',
'text/comma-separated-values',
'application/excel',
'application/vnd.ms-excel',
'application/vnd.msexcel',
'text/anytext',
'application/octet-stream',
'application/txt',
);
$expectedHeaders = array(
'SecurityID'
);
$requiredFields = array(
'SecurityID'
);
$firstLine = true;
if (in_array($_FILES['file']['type'],$csv_mimetypes))
{
if($_FILES["file"]["size"] > 0)
{
$file = fopen($filetempname, "r");
#echo $file;
while (($getData = fgetcsv($file, 10000, ",")) !== FALSE)
{
foreach($getData as $row)
{
if($firstLine)
{
var_dump($expectedHeaders);
//Set the headers:
$firstLine = false;
var_dump($getData);
$headers = array_flip($getData);
// Validate the headers:
if($headers !== $expectedHeaders)
{
echo "Invalid headers. Aborting import.";
}
Continue;
}
foreach($requiredFields as $requiredKey)
{
$value = $row[$headers[$requiredKey]];
// '0' will also match as empty(), although it is a valid value:
if(empty($value) && $value != '0' && is_numeric($value))
{
echo "Row {$requiredKey} may not be empty or has to be numeric. Aborting import.";
}
}
fclose($file);
}
}
}
}
else
{
echo "<script type=\"text/javascript\">
alert(\"Invalid File:Please Upload CSV File.\");
window.location = \"indexd.php\"
</script>";
}
}
Trying to upload/validate CSV I get below errors. IIS webserver logs doesn't give me anything..:
Invalid headers. Aborting import.
var_dump($getData); gives me below:
array(15) {
[0]=> string(14) "DataProviderID"
[1]=> string(8) "FamilyID"
[2]=> string(10) "FamilyName"
[3]=> string(10) "SecurityID"
[4]=> string(4) "Name"
[5]=> string(10) "PrimaryRic"
[6]=> string(13) "Administrator"
[7]=> string(16) "IsAdminEULocated"
[8]=> string(21) "IsAdminOnEsmaRegister"
[9]=> string(25) "IsBenchmarkOnEsmaRegister"
[10]=> string(26) "IsBenchmarkOnAdminRegister"
[11]=> string(23) "HasEUListedFundTracking"
[12]=> string(25) "HasEUListedFutureOrOption"
[13]=> string(20) "IsAdminPre2016Active"
[14]=> string(24) "IsBenchmarkPre2018Active"
}
var_dump($expectedHeaders); gives me below:
array(1) {
[0]=> string(10) "SecurityID"
}
My CSV file for testing is as below:
DataProviderID,FamilyID,FamilyName,SecurityID,Name,PrimaryRic,Administrator,IsAdminEULocated,IsAdminOnEsmaRegister,IsBenchmarkOnEsmaRegister,IsBenchmarkOnAdminRegister,HasEUListedFundTracking,HasEUListedFutureOrOption,IsAdminPre2016Active,IsBenchmarkPre2018Active
2,MSCI,MSCI Main Indices - Americas,17912,NORTH AMERICA IMI-664176,.dMINA000I0PUS,MSCI Limited,1,1,0,99,99,99,99,1

I included some var_dump's so you could see what your code does. When something doesn't work as expected ALWAYS verify your variables ("Does it hold the value I expect it does?"):
// [...]
$expectedHeaders = array(
'SecurityID'
);
var_dump($expectedHeaders);
// Will print array(
// 0 => (string) 'SecurityID'
// )
// [...] while foreach etc
//Set the headers:
$firstLine = false;
var_dump($getData);
// Will print array(
// 0 => (string) 'DataProviderID'
// 1 => (string) 'FamilyID'
// 2 => (string) 'FamilyName'
// 3 => (string) 'SecurityID'
// etc
// );
$headers = array_flip($getData);
var_dump($headers);
// Will print array(
// (string) 'DataProviderID' => 0
// (string) 'FamilyID' => 1
// (string) 'FamilyName' => 2
// (string) 'SecurityID' => 3
// etc
// )
// Validate the headers:
if($headers !== $expectedHeaders)
{
// Will always get into this if, because as you can see
// from the var_dumps, $expectedHeaders will never be
// equal to $headers - nor equal to $getData
echo "Invalid headers. Aborting import.";
}
A possible solution for your if-statement below. array_intersect will give the values that are both in $getData as in $expectedHeaders. If $getData contains more headers, those are wiped-out by array_intersect resulting in the same count (assuming order doesn't matter). If $getData has missing headers, the count of that intersection will be less than the count of $expectedHeaders.
if (
count(array_intersect($getData, $expectedHeaders))
!= count($expectedHeaders)
) {
// Wrong CSV format error
}

Related

Issues accessing Thumbnail.MimeType in EXIF read data

I'm trying to read the MimeType in the computed headers of EXIF read data but can't seem to find it, instead my loop just var dumps as if it can't find it but upon looking through the vardump i can see that Thumbnail.MimeType is indeed in the computed headers and I may be just trying to access it wrong, see code below, it accepts image upload and then uploads to a s3 bucket then I get the headers using the bucket image url.
$result = $s3->putObject([
'Bucket' => '*********',
'Key' => 'full/' . $file_name,
'SourceFile' => $temp_file_location,
'ACL' => 'public-read'
]);
$code = $result['#metadata']['statusCode'];
if ($code === 200) {
$path = "url";
}
$exif_headers = exif_read_data($path, 'EXIF');
$computed_headers = exif_read_data($path, 'COMPUTED');
//check if image has datetime original.
if (!empty($exif_headers['DateTimeOriginal'])) {
$exif_date = $exif_headers['DateTimeOriginal'];
echo $exif_date;
} else {
// if no date time original pull Thumbnail.MimeType.
if (!empty($computed_headers['Thumbnail.MimeType'])) {
$exif_mime_type = $computed_headers['Thumbnail.MimeType'];
echo $exif_mime_type;
} else { // var dump if Thumbnail.MimeType is empty.
var_dump($computed_headers);
}
}
any help would be greatly appreciated :), I feel like i am just missing something as i'm able to pull DateTimeOriginal when it is present without issues. TIA
Edit: here is the var dump
array(21) {
["FileName"]=> string(67) "5dce8027494055dce756d6bce615ACDD56-0BF6-4754-
BA08-C5FD4E0C38EC.jpeg"
["FileDateTime"]=> int(0)
["FileSize"]=> int(1309255)
["FileType"]=> int(2)
["MimeType"]=> string(10) "image/jpeg"
["SectionsFound"]=> string(30) "ANY_TAG, IFD0, THUMBNAIL, EXIF"
["COMPUTED"]=> array(7) {
["html"]=> string(26) "width="3264" height="2448""
["Height"]=> int(2448)
["Width"]=> int(3264)
["IsColor"]=> int(1)
["ByteOrderMotorola"]=> int(1)
["Thumbnail.FileType"]=> int(2)
["Thumbnail.MimeType"]=> string(10) "image/jpeg" }
["Orientation"]=> int(1)
["XResolution"]=> string(4) "72/1"
["YResolution"]=> string(4) "72/1"
["ResolutionUnit"]=> int(2)
["YCbCrPositioning"]=> int(1)
["Exif_IFD_Pointer"]=> int(102)
["THUMBNAIL"]=> array(6) {
["Compression"]=> int(6)
["XResolution"]=> string(4) "72/1"
["YResolution"]=> string(4) "72/1"
["ResolutionUnit"]=> int(2)
["JPEGInterchangeFormat"]=> int(286)
["JPEGInterchangeFormatLength"]=> int(7063)
}
["ExifVersion"]=> string(4) "0221"
["ComponentsConfiguration"]=> string(4) ""
["FlashPixVersion"]=> string(4) "0100"
["ColorSpace"]=> int(1)
["ExifImageWidth"]=> int(3264)
["ExifImageLength"]=> int(2448)
["SceneCaptureType"]=> int(0)
}
As stated in the PHP documentation the second parameter in the function call exif_read_data() represent a (comma seperated) list of sections that need to be present in file to produce a result array.
This means not that the function call will return aonly this section as result!
Change your code as below and it will work:
<?php
$result = $s3->putObject([
'Bucket' => '*********',
'Key' => 'full/' . $file_name,
'SourceFile' => $temp_file_location,
'ACL' => 'public-read'
]);
$code = $result['#metadata']['statusCode'];
if ($code === 200) {
$path = "url";
}
$exif_data = exif_read_data($path, 'EXIF');
$computed_data = $exif_data['COMPUTED'];
//check if image has datetime original.
if (!empty($exif_data['DateTimeOriginal'])) {
$exif_date = $exif_data['DateTimeOriginal'];
echo $exif_date;
} else {
// if no date time original pull Thumbnail.MimeType.
if (!empty($computed_data['Thumbnail.MimeType'])) {
$exif_mime_type = $computed_data['Thumbnail.MimeType'];
echo $exif_mime_type;
} else { // var dump if Thumbnail.MimeType is empty.
var_dump($computed_data);
}
}
?>

Problems on selecting VALUE from multidimensional ARRAY created from CSV

So, I got a CSV file that I correctly import in PHP.
function csv_to_array($filename='', $delimiter=';')
{
if(!file_exists($filename) || !is_readable($filename))
return FALSE;
$header = NULL;
$data = array();
if (($handle = fopen($filename, 'r')) !== FALSE)
{
while (($row = fgetcsv($handle, 1000, $delimiter)) !== FALSE)
{
if(!$header)
$header = $row;
else
$data[] = array_combine($header, $row);
}
fclose($handle);
}
return $data;
}
echo '<pre>';
$product_csv = csv_to_array("$underfolder/$value");
print_r($product_csv);
echo '</pre>';
This works and give show as result:
Array (
[0] => Array
(
[Name] => product name xyz
[Description] => der trefa a as sadfse
[TAGS] => tag1 tag2 tag3
[360] => yes
[VR] => no
)
)
But how I echo a VALUE of $product_csv? Like if I want to print out "product name xyz"? I tried with echo $product_csv["0"]['Name'] but without any results...
var_dump(array_keys($product_csv[0])); gives me:
array(5) { [0]=> string(7) "Name" [1]=> string(11) "Description" [2]=> string(4) "TAGS" [3]=> int(360) [4]=> string(2) "VR" }
As you can see in your var_dump(array_keys($product_csv[0])); output: string(7) "Name", there must be 3 invisible characters as Name is only 4 characters not 7.
Attempt to trim them by replacing:
$header = $row;
With:
$header = array_map('trim', $row);
It could very well be a Byte Order Mark (BOM). If you are creating this file then check the editor to see if it saves it with a BOM, and if possible disable it.

Check if string exists inside a json foreach loop

I am trying to check if a value exists inside an foreach loop from a decoded json response and compare it to my own string. I need to set $response_array['status'] to "Allowed" if $domain_to_check value exists inside the $key_info['registered_domain'] array. I tried to use in_array php function to check if value exists, however i had no success and i keep getting back "Not Allowed - Domain not listed" response even when the value is inside the array. I think that the problem is with my foreach loop but for the sake of me i can't figure whats wrong.
$domain_to_check = 'domain-name.com';
$data = json_decode($returnCheckValue,true);
$key_response = $data['result'];
if ($key_response == 'success'){
foreach ($data['registered_domains'] as $key_domain_info) {
$key_listed_domain = $key_domain_info['registered_domain'];
if ($key_response == 'success' && in_array($domain_to_check, $key_listed_domain)) {
$response_array['status'] = 'Allowed';
}
else {
$response_array['status'] = 'Not Allowed - Domain not listed';
}
}
}
else {
$response_array['status'] = 'Not Allowed - Wrong Key';
}
echo json_encode($response_array);
Here is how my var_dump(); of the $data looks like
array(9) { ["result"]=> string(7) "success" ["max_allowed_domains"]=> string(1) "3" ["registered_domains"]=> array(2) { [0]=> array(5) { ["id"]=> string(2) "60" ["lic_key_id"]=> string(2) "51" ["lic_key"]=> string(13) "93248cqkdj21as" ["registered_domain"]=> string(19) "domain-name-2.com" ["item_reference"]=> string(1) "1" } [1]=> array(5) { ["id"]=> string(2) "58" ["lic_key_id"]=> string(2) "51" ["lic_key"]=> string(13) "93248cqkdj21as" ["registered_domain"]=> string(14) "domain-name.com" ["item_reference"]=> string(3) "443" } } }
Relate below code with your code. This code is working.
$domain_to_check = "domain-name.com";
$test = array("registered_domains" => array("registered_domain" => "domain-name-2.com"), array("registered_domain" => "domain-name.com"));
foreach($test as $val) {
if($val['registered_domain'] == $domain_to_check) {
$result = 'success';
break;
} else {
$result = 'failure';
}
}
echo $result;
Use php strpos
$domainStringFound = strpos($key_listed_domain, $domain_to_check);
if ($key_response == 'success' && $domainStringFound !== false) {
$response_array['status'] = 'Allowed';
}

Splitting array if empty value

I am trying to split an array if one of the lines has an empty value. My array is being exported to a csv and has multiple lines of data, if the data is not complete it will be sent to a uncomplete csv and if it is complete it will be sent a complete csv.
This is what my array structure looks like the blank field on the first line is on email (this line should be split out of the array:
array(2) {
[0]=> array(6) {
["Username"]=> string(47) " STARRY NIGHT CINEMA - RISE OF THE GUARDIANS "
["Email"]=> string(0) ""
["Location"]=> string(1) "1"
["Type"]=> int(1)
["Title"]=> string(47) " STARRY NIGHT CINEMA - RISE OF THE GUARDIANS "
["Description"]=> string(491) "the Tooth Fairy"
}
[1]=> array(6) {
["Username"]=> string(26) "Maui Nui Botanical Gardens"
["Email"]=> string(18) "info#mnbg.org"
["Location"]=> string(1) "1"
["Type"]=> int(1)
["Title"]=> string(26) "Maui Nui Botanical Gardens"
["Description"]=> string(50) "Conserving Hawaiian Plants & Cultural Heritage"
}
}
Writing to my csv:
$fp = fopen('entries.csv', 'w');
foreach ($entries as $fields) {
fputcsv($fp, $fields);
}
fclose($fp);
if (!copy("http://www.simonstaton.co.uk/entries.csv", "entries.csv")) {
echo ("failed to copy file");
};
I have no idea where to start with this and as to what function I should use so any advice is greatly appreciated.
Simon
To separate the entries by complete or incomplete you can open two files for writing. One to contain each.
// filenames
$fn_complete = 'entries.csv';
$fn_incomplete = 'incomplete_entries.csv';
// file pointers
$fp_complete = fopen($fn_complete, 'w');
$fp_incomplete = fopen($fn_incomplete, 'w');
// write CSVs
foreach ($entries as $fields) {
if (in_array('', $fields))
fputcsv($fp_incomplete, $fields);
else
fputcsv($fp_complete, $fields);
}
fclose($fp_complete);
fclose($fp_incomplete);
if (!copy('http://www.simonstaton.co.uk/' . $fn_complete, $fn_complete)) {
echo ('failed to copy file ' . $fn_complete);
};
if (!copy('http://www.simonstaton.co.uk/' . $fn_incomplete, $fn_incomplete)) {
echo ('failed to copy file ' . $fn_incomplete);
};
You can check if any of the values in your array is empty like this:
in_array('', $array)
so it then you can do a simple if
if(in_array('', $array)) {
//Do whatever you have to do to slip your array. I don't understand exactly what you want the end result to look like .
}
First pack your CSV data into an array using fgetcsv(). Then use a loop to search for "".
Exemplar:
$row = 1;
if (($resource = fopen("example.csv", "r")) !== false) {
while (($data = fgetcsv($resource, 1000, ",")) !== false) {
$num = count($data);
$row++;
for ($c=0; $c < $num; $c++) {
if ($data[$c] == "") {
// operate
}
}
}
fclose($handle);
}
By the way, don't use the split() function. Use preg_split().
http://php.net/manual/en/function.fputcsv.php

Navigate to a $_FILE array to get particular array of files with different name[]

Overview
I have a multi-part form that has four file upload fields and three of these are dynamically added (using JavaScript).
<input type="file" name="OneCertificate" />
<input type="file" id="MultipleCertificate[1] "name="MultipleCertificate[]" />
<input type="file" id="MultipleCertificate[2] "name="MultipleCertificate[]" />
// more if Add button is pressed
Here is the output of var_dump($_FILES):
["OneCertificate"]=> array(5) {
["name"]=> string(6) "DE.pdf"
["type"]=> string(15) "application/pdf"
["tmp_name"]=> string(24) "C:\xampp\tmp\php37C2.tmp"
["error"]=> int(0)
["size"]=> int(103845)
}
// **Notice the attributes are all in their own arrays**
["MultipleCertificate"]=> array(5) {
["name"]=> array(2) { [0]=> string(6) "DE.pdf" [1]=> string(6) "DE.pdf" }
["type"]=> array(2) { [0]=> string(15) "application/pdf" [1]=> string(15) "application/pdf" }
["tmp_name"]=> array(2) { [0]=> string(24) "C:\xampp\tmp\phpD941.tmp" [1]=> string(24) "C:\xampp\tmp\phpD942.tmp" }
["error"]=> array(2) { [0]=> int(0) [1]=> int(0) }
["size"]=> array(2) { [0]=> int(103845) [1]=> int(103845) }
}
// and so on...
Below is how I upload each file:
function upload_file($field_name)
{
// timestamp name: http://stackoverflow.com/questions/7457152/did-not-select-a-file-to-upload-when-uploading-using-codeigniter
$the_date= date('Y/n/j h:i:s');
$replace = array(":"," ","/");
$new_name = str_ireplace($replace, "-", $the_date);
$config['upload_path'] = './uploads/';
$config['file_name'] = $new_name;
$config['allowed_types'] = 'pdf|jpg|jpeg|png';
$this->load->library('upload');
$this->upload->initialize($config);
// Get OneCertificate the normal way since it will only have one file content
if ( $field_name == 'OneCertificate' ) {
if ( ! $this->upload->do_upload($field_name)) {
return array('error' => $this->upload->display_errors());
} else {
$file_data = array('upload_data' => $this->upload->data());
}
// Method for MultipleCertificate
} else {
for ($i = 0; $i < count($_FILES[$field_name]['name']); $i++) {
if ( ! $this->upload->do_upload($_FILES[$field_name]['name'][$i])) {
$file_data = array('error' => $this->upload->display_errors());
} else {
$file_data = array('upload_data' => $this->upload->data());
}
} // END for loop
}
return $file_data;
}
The Problem
I noticed that the format of OneCertificate works since all of its information are in a single array compared to MultipleCertificate that has each attribute in its own array.
The first manages to successfully upload a file but the latter throws a You did not select a file to upload.
How do I transform and/or retrieve the form of MultipleCertificate into OneCertificate?
Note: This is the form I need since I will assign the arrays created to $OneCertificate and $MultipleCertificate for database insertion.
For anyone who had a problem like mine regarding how $_FILES handles file arrays, hohner's comment above solved the problem.
Here is the SO link to the answer.
Basically my "looping to the inner arrays of the $_FILE array" goes like this:
function do_upload($file_name)
{
$this->load->library('upload');
$this->total_count_of_files = count($_FILES[$file_name]['name']);
// timestamp name: https://stackoverflow.com/questions/7457152/did-not-select-a-file-to-upload-when-uploading-using-codeigniter
$date_timestamp = date('Y/M/j h:i:s');
$replace = array(":"," ","/");
$new_name = $file_name.'-'.$this->session->userdata('AccreditNo').'-'.str_ireplace($replace, '', $date_timestamp);
for($i = 0; $i < $this->total_count_of_files; $i++) {
// userfile is arbitrary, it will not reflect on the final array
$_FILES['userfile']['name'] = $_FILES[$file_name]['name'][$i];
$_FILES['userfile']['type'] = $_FILES[$file_name]['type'][$i];
$_FILES['userfile']['tmp_name'] = $_FILES[$file_name]['tmp_name'][$i];
$_FILES['userfile']['error'] = $_FILES[$file_name]['error'][$i];
$_FILES['userfile']['size'] = $_FILES[$file_name]['size'][$i];
$config['file_name'] = $new_name.'-'.$i;
$config['upload_path'] = "./uploads/$file_name";
$config['allowed_types'] = 'pdf|jpg|jpeg|png';
$config['max_size'] = '0';
$this->upload->initialize($config);
if ( ! $this->upload->do_upload()) {
$file_data = array('error' => $this->upload->display_errors());
} else {
$file_data = array("file_{$i}" => $this->upload->data());
}
}
return $file_data;
}
File data will now contain the assembled attributes of one file to be inserted to the database! (how I want it to be in this case)

Categories