PHP - make $_FILES filenames safe - php

I have an form that contains an "attachments" field, allowing a user to add multiple attachments. Each attachment is then uploaded but before doing so, each file name is made safe using the following function.
function safeFile($file) {
$lower = strtolower($file);
$trim = rtrim($lower, '.');
$regex = array('#[^A-Za-z0-9\.\_\- ]#');
return trim(preg_replace($regex, '', $trim));
}
So far so good.
I'm then json encoding the file names to store in the database. using the following:
json_decode($_FILES['attachment']['name']);
This outputs the following in the database:
["FILE.jpg", "OTHER.jpg"]
This works, however I'm also trying to call the safeFile() function so that the same action is applied before inserting into the database as it does when uploaded.
I tried using the following which did not work.
json_encode( safeFile($_FILES['add_attachment']['name']) );
To get around this, thinking logically, would I have to create a foreach loop, then making each individual file name safe, then return an array?
Could someone please shove me in the right direction?

You don't need a foreach loop
You need to use array_map() like this
array_map("safeFile", $_FILES['add_attachment']['name']);
Also, what I think you need to be using is json_encode() not json_decode

Related

how to loop through a text file in php to find a specific line of text

I have made a program that lets you enter the username and password then it stores it in a text file and when i want to login i want to make it so it loops through the text file that has the usr/pass in to find if you entered your credentials in correctly. I'm not sure how to do this. please can somebody help
Example text.txt file:
$ cat text.txt
text1|answer1
text2|answer2
text3|answer3
Example code:
cat test2.php
<?php
$text="text1";
$file="text.txt";
$f = fopen($file, 'r');
while($data = fgets($f))
{
$ar_data=explode('|',$data);
if($ar_data[0]==$text) {
echo "looking for: ".$ar_data[1]."\n";
}
}
Example usage:
$ php test2.php
looking for: answer1
The text fileis not a good way for verify user credentials. You should try sql database. sqlite3 for example.
You can just hard code them in an array:
$passwords = ['someuser' => 'password'];
If you really want to store them in a file, so you can change them (for example) without editing the code, One way is to use something like this:
$passwords = ['someuser' => 'password'];
file_put_contents('passwords.php', '<?php return '.var_export($passwords,true).';');
This will create a file with something this in it (white space not withstanding):
<?php return array('someuser' => 'password');
Then when you need to import it into code you can simply use
$passwords = require 'passwords.php';
Which will put the contents of that file into that variable. Then you can check them really easily like so:
$passwords = require 'passwords.php';
if(isset($passwords[$user]) && $passwords[$user] == $password){
//do something when logged in
}
You can also modify the array and then save it:
$passwords = require 'passwords.php';
$passwords['someuser'] = $new_password;
file_put_contents('passwords.php', '<?php return '.var_export($passwords,true).';');
Of course you can even edit the passwords manually in the file. Sort of like a config file.
As I mentioned in the comments, it's better to use the DB, encryption and what not but as you said
this is only for me and someone else
As long as you don't have any third party data, and your ok with the security implications of this, then you can probably squeak by with the above.
To explain it:
Var Export converts arrays to valid PHP code, but in a string format. Then if we add the PHP open tag <?php, the return call return and the ending ; to it and save it in a PHP file, we now have a valid PHP file with dynamic passwords saved in it as an array.
When you have such a file that returns an array, you can inject that into a variable just by setting it like I showed above. Then it's a simple matter of checking to see if everything matches up.
Performance wise your offloading most of the penalty of this to saving the file, importing an array like this is very fast as is the key lookup. Much faster then iterating though a file and trying to parse the data from it.
You'll have to get the paths and filenames right and all that Jazz, but it should be pretty strait forward.

Writing values to INI file

I'm trying to store multiple data and then at the end go a head and push the data into the new .ini file. I found solutions which works but I want to get all the data first and then update the file at the end but the solutions i found updates the file straight away!
A solution I liked and worked is located: https://stackoverflow.com/a/36997282/6613233
I am trying to allow it gather information and then push it to the file at the end. My own attempt at this is below but i keep getting array array in my ini file.
Code:
$fbsettingsDB = parse_ini_file("location.ini", true);
$fbsettingsDB["id"]["value"] = $_POST['fbconfigid'];
$fbsettingsDB["location"]["value"] = $_POST['fbconfigcty'];
file_put_contents('location.ini', implode("\n", $fbsettingsDB));
The above is how I want to collect data. I have a bunch of code which goes in and out of statements, I want it to go ahead.. Assign the values required and at the very end go ahead and put the contents in the file like shown above.
Using the referred code i would then have to do:
config_set("location.ini", "id", "value", $_POST['fbconfigid']);
config_set("location.ini", "location", "value", $_POST['something']);
config_set("location.ini", "result", "value", $_POST['somethingelse']);
Which overwrites the file every time which in my opinion is just crazy! Overkill for my idea, there is obviously some way that can suit my needs so i can just call the function once after making a list of edit/changes and then when i call the function it grabs all my changed data and saves the file the way i want it!
I'll try to explain first why your code doesn't work, compared to the other.
Your inifile-array is build up of a nested array, $array[section][item] = value. The first dimension has the section names. The second dimension is the name of the items in the sections. So $fbsettingsDB["location"] contains an array of items, of which "value" is one.
Implode doesn't check if the array is nested. It just takes the first dimension (the sections) and tries to treat their values as a string. Since those values are actually arrays of items, PHP just converts that to the text 'array'.
Apart from that, you can't just implode the whole array. Section names should be enclosed in square brackets, so there is a little more work to do in that regard too.
If you check the solution in the answer you referred to, you'll see that it contains a loop which takes care of the first layer, the sections.
The array of items of each section is converted separately with implode, which is then prefixed by the section name in square brackets, and the whole lot is appended to the end result.
So, your intention here: You don't want to set a value and write it back to file at once, but update multiple values and only write the end result to disk. Well, fortunately the function doesn't have to be atomic. It already performs three separate actions: loading from disk, modifying the data, and serializing it back to disk. Let's see if those can be isolated in separate functions:
Read the data. Well, hardly worth to make a function, but it may make your application somewhat more consistent if you use the same naming et cetera in a collection of related functions.
Note: I just wrote these from scratch. No PHP at hand to test, so they might contain minor syntactical errors.
So here it is:
// Loads ini file data
function config_read($config_file) {
return parse_ini_file($config_file, true);
}
Setting the config in the loaded data. Again, hardly worth to have a function, but it adds readability and hides how exactly the ini file data is built up, so you don't have to worry about implementation details when using it. Note that the array is passed by reference. The array you specify is updated. The function doesn't return a value.
// Update a setting in loaded inifile data
function config_set(&$config_data, $section, $key, $value) {
$config_data[$section][$key] = $value;
}
Then writing it:
// Serializes inifile config data back to disk.
function config_write($config_data, $config_file) {
$new_content = '';
foreach ($config_data as $section => $section_content) {
$section_content = array_map(function($value, $key) {
return "$key=$value";
}, array_values($section_content), array_keys($section_content));
$section_content = implode("\n", $section_content);
$new_content .= "[$section]\n$section_content\n";
}
file_put_contents($config_file, $new_content);
}
Note that so far I didn't modify any of the code. I just wrapped it in separate functions. If you like, you could even call those functions in another function, so you still got the shorthand to write everything to disk at once. You'll have the original functionality, but without having duplicate code:
// Short-hand function for updating a single config value in a file.
function config_set_file($config_file, $section, $key, $value) {
$config_data = config_read($config_file);
config_set($config_data, $section, $key, $value)
config_write($config_file, $section, $key, $value);
}
So, now you got this collection of functions, you can decide which to use based on the situation. If you just want to update a single value, you might as well write this:
config_set_file("location.ini", "id", "value", $_POST['fbconfigid']);
But if you have multiple configs to set, you can do this:
// Load
$config_data = config_read("location.ini");
// Set multiple values
config_set($config_data, "id", "value", $_POST['fbconfigid']);
config_set($config_data, "location", "value", $_POST['something']);
config_set($config_data, "result", "value", $_POST['somethingelse']);
// Save
config_write($config_data, $config_file);
I can imagine you can add other shorthands, like config_set_array_file, which you could call like this.. I'll leave the implementation of this one to you for exercise. ;)
array_config_set_file($config_file, array(
"id" => $_POST['fbconfigid'],
"location" => $_POST['something'],
"result" => $_POST['somethingelse']));
And after that, you can poor all this into an IniFile class to make it even nicer. :)

PHP: Extract fdf fields as an array from a PDF

i want to extract the available fields as an array from a fillable pdf.
an array like: array('firstname','secondname','address');
i do not need the values for those fields, if they are filled.
what is easiest way to do that using PHP?
under online documentation for "fdf_next_field_name" the following example is given that you can modify to store the field names into an array
<?php
$fdf = fdf_open($HTTP_FDF_DATA);
for ($field = fdf_next_field_name($fdf); $field != ""; $field = fdf_next_field_name($fdf, $field)) {
echo "field: $field\n";
}
?>
I upvoted Murray's answer because her was in ernest and I am pretty sure that he is right pre php 5.3
Sadly, pecl fdf is no more.
Thankfully, one "noah" made a comment on the php documentation with a preg_match_all regex solution to the problem. Included here with slight modifications for clarity. Long live noah.
function parse($text_from_file) {
if (!preg_match_all("/<<\s*\/V([^>]*)>>/x",$text_from_file,$out,PREG_SET_ORDER))
return;
for ($i=0;$i<count($out);$i++) {
$pattern = "<<.*/V\s*(.*)\s*/T\s*(.*)\s*>>";
$thing = $out[$i][2];
if (eregi($pattern,$out[$i][0],$regs)) {
$key = $regs[2];
$val = $regs[1];
$key = preg_replace("/^\s*\(/","",$key);
$key = preg_replace("/\)$/","",$key);
$key = preg_replace("/\\\/","",$key);
$val = preg_replace("/^\s*\(/","",$val);
$val = preg_replace("/\)$/","",$val);
$matches[$key] = $val;
}
}
return $matches;
}
I expect that someone will get fedup with the lack of true fdf support in php and fix this.
Since we are all probably after the same basic workflow if you are reading this question, then you should know that the basic workflow that I am following is:
download normal pdf form.
use libreoffice to make it a pdf form with named fields.
use pdftk to turn it into a fdf file
use this function to figure out what values the form needs.
populate a flat php array with the correct variables defined (from db/whatever)
use pdf_forge to create a new fdf with the values pre-filled
use pdftk again to create a new pdf from fdf+original-pdf with the variables (from db/whatever)
profit
HTH
-FT
If you control the pdf and just want the keys, the following will work. Uses php, no other libraries (good if you host doesn't have them).
Set the pdf submit button to html and set the page to the address where your php code will run.
$q_string = file_get_contents("php://input");
parse_str($q_string , $pdf_array);
$pdfkeys = array_keys($pdf_array);
The html query string, from the pdf file, is put into the variable $q_string. It is then parsed into an array called $pdf_array. $pdf_array holds all of the keys and values. Then array_keys() is used to put all the keys into $pdfkeys as you wanted.
I had come here looking how to read pdf values to put into a db, and finally after some more poking around came up with the above. Hopefully meets some people's needs. xfdf can also work, but you will need to parse as xml then -- this was simpler for me.
I get a normal post from PDFs submitting to my server, but not in the $_POST array. You just have to parse it from php://input:
$allVars = file_get_contents("php://input");
parse_str($allVars, $myPost);
foreach($myPost as $key => $value) {
$allKeys[] = $key;
}

PHPFlickr script...could this be cleaner/leaner?

OK, here's my dilemma:
I've read all over about how many guys want to be able to display a set of images from Flickr using PHPFlickr, but lament on how the API for PhotoSets does not put individual photo descriptions. Some have tried to set up their PHP so it will pull the description on each photo as the script assembles the gallery on the page. However, the method has shown how slow and inefficient it can be.
I caught an idea elsewhere of creating a string of comma separated values with the photo ID and the description. I'd store it on the MySQL database and then call upon it when I have my script assemble the gallery on the page. I'd use explode to create an array of the photo ID and its description, then call on that to fill in the gaps...thus less API calls and a faster page.
So in the back-end admin, I have a form where I set up the information for the gallery, and I hand a Set ID. The script would then go through and make this string of separated values ("|~|" as a separation). Here's what I came up with:
include("phpFlickr.php");
$f = new phpFlickr("< api >");
$descArray = "";
// This will create an Array of Photo ID from the Set ID.
// $setFeed is the set ID brought in from the form.
$photos = $f->photosets_getPhotos($setFeed);
foreach ($photos['photoset']['photo'] as $photo) {
$returnDesc = array();
$photoID = $photo['id'];
$rsp = $f->photos_getInfo($photoID);
foreach ($rsp as $pic) {
$returnDesc[] = htmlspecialchars($pic['description'], ENT_QUOTES);
}
$descArray .= $photoID."|~|".$returnDesc[0]."|~|";
}
The string $descArray would then be placed in the MySQL string that puts it into the database with other information brought in from the form.
My first question is was I correct in using a second foreach loop to get those descriptions? I tried following other examples all over the net that didn't use that, but they never worked. When I brought on the second foreach, then it worked. Should I have done something else?
I noticed the data returned would be two entries. One being the description, and the other just an "o"...hence the array $returnDesc so I could just get the one string I wanted and not the other.
Second question is if I made this too complicated or not. I like to try to learn to write cleaner/leaner code, and was looking for opinions.
Suggestions on improvement are welcome. Thank you in advance.
I'm not 100% sure as I've just browsed the source for phpFlickr, and looked the the Flickr API for the getInfo() call. But let me have a go anyway :)
First off, it looks like you shouldn't need that loop, like you mention. What does the output of print_r($rsp); look like? It could be that $rsp is an array with 1 element, in which case you could ditch the inner loop and replace it with something like $pic = $rsp[0]; $desc = $pic['description'];
Also, I'd create a new "description" column in your database table (that has the photo id as the primary key), and store the description in their on its own. Parsing db fields like that is a bit of a nightmare. Lastly, you might want to force htmlspecialchars to work in UTF8 mode, cause I don't think it does by default. From memory, the third parameter is the content encoding.
edit: doesn't phpFlickr have its own caching system? Why not use that and make the cache size massive? Seems like you might be re-inventing the wheel here... maybe all you need to do is increase the cache size, and make a getDescription function:
function getDescription ($id)
{
$rsp = $phpFlickr->photos_getInfo ($id);
$pic = $rsp[0];
return $pic['description'];
}

Validating Uploaded Files Server Side

I have some CSV files that I need uploaded to a site I'm writing in CodeIgniter.
I need to validate the CSV to make sure they contain various info, column counts match up and stuff like that.
Does CI have any sort of plugin to make this easy?
After the file is uploaded, open it and use fgetcsv to go through it line by line.
http://us3.php.net/manual/en/function.fgetcsv.php
It creates an array (in that link, the array in the first example is called $data), if you are looking for column count, you can find it with sizeof($data). If you need specific column content or types, you can use a wide variety of regex to figure it out. Say column 3 has to be an email address:
$column_size = 8;
while($data=fgetcsv($p))
{
if ( sizeof($data) < $column_size )
{
// handle wrong column count error here
}
if ( !is_email($data[2] ) // is_email is a fictional function
{
// handle error here
}
// other checks...
}
I don't know if there is a CI plugin for it, but it probably couldn't make it much easier anyway.

Categories