Updating a PHP array of POST datas, before processing them - php

I need to apply some functions to a key items inside an array before moving on with the whole array, but I probably miss something.
Here is my code:
// Get generated datas
$data_post = $this->input->post('form_data'); // Need to update this array
foreach( $data_post as $data ){
$data['password'] = password_encrypt($data['password']);
var_dump($data); // Password encryption succeed
}
var_dump($data_post); // But here, the password is still the same, no encryption applied
So as commented in the CODE section, how should I update the main $data_post array with the modifications made in foreach() ?

Inside a foreach, data isn't passed by reference. This means that modifying the variable $data doesn't modify $data_post. You can modify the original array in more than one way, but here is how I would do it:
foreach( $data_post as $key => $data ){
$data_post[$key]['password'] = password_encrypt($data['password']);
}
Note that this presumes that $data_post contains multiple sub arrays, each with the password key (or else notices will be thrown).

Try this:
$data_post = $this->input->post('form_data'); // Need to update this array
foreach( $data_post as $k=>$v ){
if($k == "password"){
$data_post[$k] = password_encrypt($v);
}
}
var_dump($data_post);

Related

Unpacking an array_value()'d $_POST array

I'm having some issues that I suspect are from misunderstanding how to handle $_POST data from a web form. It's racking my brains, because my method works in one scenario, but breaks in its successor.
In a nutshell: I can call key=>value pairs of $_POST in a method, but I can't manipulate the $_POST array itself, which always returns as 1.
Initial Scenario. Refer to comments for context & gripes. This method works:
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$post = $_POST; // I'm aware $_POST is a superglobal and can be called within the method
$cms->addPage($table, $post);
}
addPage() Method from CMS class:
public function addPage($table, $post) {
global $db; // SQL object declared in config
$url = preg_replace('/\s+/', '-', $post['pageTitle']);
$vals = array($post['pageTitle'], $post['isRoot'], $post['metaTitle'], $post['metaDesc'], $post['pageCont'], $url, $post['dateCreated'], $post['pageBanner']);
$cols = array("pageTitle", "isRoot", "metaTitle", "metaDesc", "pageCont", "pageURL", "dateCreated", "pageBanner");
$types = "sissssss";
$db->prep_Insert($table, $cols);
$db->bind_Prep($types, $vals); // This method unpacks the $vals array with ...
$db->execute_Prep();
$db->close_Prep();
$_SESSION['success'] = 'Page Updated';
header('Location: ' . DIRADMIN . 'manage/pages');
exit();
}
This works fine. Pops right up in the database, and bob's your uncle. But, this CMS should be able to handle multiple form objects, and I don't want to write an add / update method for every custom feature a client might want. So I came up with this:
public function addContent($table, $post, $types) {
global $db;
$cols = self::getColumns($table); // Helper method I wrote to get column names from the table being added to
array_shift($cols); // AUTO_INCREMENT is set in database, so knock off the ID row
/* This is where it falls apart. All I want is to take the $_POST array
I got from the form and reduce it from associative to indexed.
The array_values() should do this, right? */
$post = array_values($post);
// $post = array_values($_POST);
/* Also doesn't work. It doesn't matter if I pass forward the
$_POST array as a parameter, or if I call it directly here. */
/* Second attempt at getting $_POST into an indexed array. I don't need the keys. */
/*$i = 0;
$vals = array();
foreach ($_POST as $key => $value) {
$vals[$i] = $value;
$i++;
}*/
$db->prep_Insert($table, $cols);
$db->bind_Prep($types, $post); // This is where I got the initial unpacking error; can't unpack associative arrays. Okay, I'll use array_value($_POST). Except, that always just outputs 1, and breaks the prep statement anyway.
$db->execute_Prep();
$db->close_Prep();
$_SESSION['success'] = 'Page Updated';
header('Location: ' . DIRADMIN . 'manage/' . $table);
exit();
}
So to reiterate, for some reason I can get $_POST data by its individual key=>value pairs in the initial method, but if I try to manipulate the $_POST array in any way (array_keys(), reset(), foreach loop, etc), it will output as 1. print_r() outputs 1, var_dump() outputs blank, and in the exception message it returns as 1.
Is there some limitation or rule to handling $_POST data that I'm not getting? I can't figure out why I can get key value pairs, but otherwise can't manipulate it at all.

PHP - array_push converting JSON array to object

I am trying to add an object ("new_item") to an array if objects in a master JSON object ("master"). If the new object ID already exists in the array I first remove that object from the array before then adding it again afterwards (so there is only one entry per ID).
For some reason when I do this the Array of objects gets converted to a list of objects which I don't want.
This doesn't happen if I only remove the duplicate or allow duplicates, it only seems to happen when I remove one element and then add another.
$object = '{"master":[{"id":"1","author":"A"},{"id":"2","author":"B"}]}';
$object = json_decode($object);
$new_item = '{"id":"2","author":"B"}';
$new_item = json_decode($new_item);
foreach ( $object->master as $key => $item ) {
if ( $item->id == $new_item->id ) {
unset($object->master[$key]);
}
}
if ( count($object->master) == 0 ) {
$object->master = Array($new_item);
} else {
array_push($object->master, $new_item);
}
echo json_encode($object);
Outputs
{"master":{"0":{"id":"1","author":"A"},"2":{"id":"2","author":"B"}}}
As oppose to
{"master":[{"id":"1","author":"A"},{"id":"2","author":"B"}]}
json_encode() only encodes an array as a JSON array if the indexes are sequential starting from 0. Otherwise, it's encoded as an object. Since you do unset($object->master[$key]), you create a gap in the indexes, so you get an object, as there's no other way to indicate that the array doesn't have anything at index 1.
You can use array_values() to renumber the indexes, to get rid of the gap.
There's no need to check if the count is 0 before pushing the new item, since you can push onto an empty array.
array_push($object->master, $new_item);
$object->master = array_values($object->master);
You say that the problem doesn't happen if you only remove the duplicate without adding another. It should still happen, unless the duplicate happens to be the last element. Then there's no gap in the index sequence, so it meets the criteria to be encoded as an array.
If IDs are unique, another solution would be to simply replace the duplicate with the new item, instead of unsetting it and later pushing the new item.
$found = false;
foreach ( $object->master as $key => $item ) {
if ( $item->id == $new_item->id ) {
$object->master[$key] == $new_item;
$found = true;
break;
}
}
if (!$found) {
$object->master[] = $new_item;
}
U can use this:
$object = array_values($object);

Remove first element from simple array in loop

This question has been asked a thousand times, but each question I find talks about associative arrays where one can delete (unset) an item by using they key as an identifier. But how do you do this if you have a simple array, and no key-value pairs?
Input code
$bananas = array('big_banana', 'small_banana', 'ripe_banana', 'yellow_banana', 'green_banana', 'brown_banana', 'peeled_banana');
foreach ($bananas as $banana) {
// do stuff
// remove current item
}
In Perl I would work with for and indices instead, but I am not sure that's the (safest?) way to go - even though from what I hear PHP is less strict in these things.
Note that after foreach has run, I expected var_dump($bananas) to return an empty array (or null, but preferably an empty array).
1st method (delete by value comparison):
$bananas = array('big_banana', 'small_banana', 'ripe_banana', 'yellow_banana', 'green_banana', 'brown_banana', 'peeled_banana');
foreach ($bananas as $key=>$banana) {
if($banana=='big_banana')
unset($bananas[$key]);
}
2nd method (delete by key):
$bananas = array('big_banana', 'small_banana', 'ripe_banana', 'yellow_banana', 'green_banana', 'brown_banana', 'peeled_banana');
unset($bananas[0]); //removes the first value
unset($bananas[count($bananas)-1]); //removes the last value
//unset($bananas[n-1]); removes the nth value
Finally if you want to reset the keys after deletion process:
$bananas = array_map('array_values', $bananas);
If you want to empty the array completely:
unset($bananas);
$bananas= array();
it still has the indexes
foreach ($bananas as $key => $banana) {
// do stuff
unset($bananas[$key]);
}
for($i=0; $i<count($bananas); $i++)
{
//doStuff
unset($bananas[$i]);
}
This will delete every element after its use so you will eventually end up with an empty array.
If for some reason you need to reindex after deleting you can use array_values
How about a while loop with array_shift?
while (($item = array_shift($bananas)) !== null)
{
//
}
Your Note: Note that after foreach has run, I expected var_dump($bananas) to return an empty array (or null, but preferably
an empty array).
Simply use unset.
foreach ($bananas as $banana) {
// do stuff
// remove current item
unset($bananas[$key]);
}
print_r($bananas);
Result
Array
(
)
This question is old but I will post my idea using array_slice for new visitors.
while(!empty($bananas)) {
// ... do something with $bananas[0] like
echo $bananas[0].'<br>';
$bananas = array_slice($bananas, 1);
}

PHP split and mongodb

ok, this might sound strange, but i have a form and our business wants to track what is getting changed, when a user adds a new lead etc.
So i set up a function that does the following
function savedata($data){
$collection = $this->db->retail_logs;
$this->data = explode('|', $data['data']);
print_r($this->data);
try {
$collection->update(
array($this->data['0']=>$this->data['1'],$this->data[2]=>$this->data[3]),
array("date"=> date("d.m.Y"), "time"=>date("H:i:s"),"whochanged"=>$_COOKIE['CRMUIDkey']), // new lead document to insert
array("upsert" => true, "safe" => true)
);
} catch (Exception $e) {
// Something went wrong ..
}
}
it is basiclly a log file.
but as you may be able to see the $data sends data though like tradingname|ABC|owner|ownerID
But if I want to add to that i would need to run a loop or a foreach I am wondering what is the best way to make sure all teh data gets saved and not just data[0] to 3 so say they send 16 fields and values in it I need a foreach or something to split it.
It appears that you want to map the $data['data'] into key=>value pairs (an associative array). You want to be very careful about what fields you allow in this format especially since it looks like user-provided data (or data they can modify in a post request?). For example, a malicious user could update or add to another user's account if you aren't checking the allowed keys before doing the upsert.
To convert the $data string you want to do something like:
<?php
// Keys that can be updated
$allowed = array('tradingname','owner');
// Sample data
$data = 'tradingname|ABC|owner|ownerID|badkey|foo';
// Split into arrays based on '|' delimiter
preg_match_all("/([^\|]+)\|([^\|]+)/", $data, $keypairs);
// Combine matches into key => value array
$keypairs = array_combine($keypairs[1], $keypairs[2]);
// Sanity check to create $criteria
foreach ($keypairs as $key => $value) {
if (in_array($key, $allowed)) {
// Perhaps do some extra sanity checking that $value is expected format
$criteria[$key] = $value;
} else {
// Log and/or bailout as appropriate
echo "Ignoring: [$key] => [$value]\n";
}
}
// Criteria should now be reasonable to use in $collection->update(..) upsert
print_r($criteria);
?>
Send your data as json. And then use json_decode to convert it to the array you want.

Build a json in php from POST data

I need to update a json list of object via url post data. For example, with url:
http://myweb.com/index.php?name=Peter&surname=Brown
in php, using get method:
$name = $_GET["name"];
$surname = $_GET["surname"];
$json = array();
$json["nombre"] = $name;
$json["lat"] = $lat;
$data[] = $json;
$json_end= json_encode($data);
and json_end efectively is done like I want:
[{"name":"Peter","surname":"Brown"}]
My question is about how I can do it incrementing the json, in order to build an array like:
[{"name":"Peter","surname":"Brown"}]
[{"name":"newname","surname":"newsurname"}]
// and so on
each time user use the url with new parameters.
Do I need to write to a file, or to database? Any tips will be apreciated.
The idea is to be able that any user can add some dat using url. I tried to store the json to a fiel but the storing is durable only along the current session.
<?
/* This needs to be at the top of your file, without ANYTHING above it */
session_start();
/* ... */
if(!array_key_exists('entries', $_SESSION))
{
$_SESSION['entries'] = array();
}
$_SESSION['entries'][] = array("name" => $_GET["name"], "surname" => $_GET["surname"]);
$json_string = json_encode($_SESSION['entries']);
This would produce a single JSON. However I don't know whether you meant to or not, but your output is a series of separate JSONs. You could do this by replacing the last line above with:
$json_string = '';
foreach($_SESSION['entries'] as $entry){
$json_string.= json_encode($entry) . "\n";
}
You would also probably want a way to reset/empty the array. In which case I'd change the if test from:
if(!array_key_exists('entries', $_SESSION))
to:
if(!array_key_exists('entries', $_SESSION) || array_key_exists('reset', $_GET))
Which you could use by visiting
http://myweb.com/index.php?reset
Edit: If somewhere you add the following code:
foreach($_SESSION['entries'] as $id=>$entry){
printf("%2d: %s\n", $id, json_encode($entry));
}
You'll get a list of the json elements enumerated by their respective keys. For example, it might look like:
0: "[{\"name\":\"Peter\",\"surname\":\"Brown\"}]"
1: "[{\"name\":\"newname\",\"surname\":\"newsurname\"}]"
2: "[{\"name\":\"George\",\"surname\":\"Washington\"}]"
3: "[{\"name\":\"John\",\"surname\":\"Adams\"}]"
If you then add the following code:
if(array_key_exists('del', $_GET) && is_numeric($_GET['del']))
{
$key = (int)$_GET['del'];
if(array_key_exists($key, $_SESSION['entries']))
{
unset($_SESSION['entries'][$key]);
}
else
{
printf('<strong>ERROR: $_GET['del'] = %d but $_SESSION['entries'][%d] doesn't exist.</strong>', $key, $key);
}
}
you'll be able to delete individual json entries by specifying id as the del GET parameter.
For example,
http://myweb.com/index.php?del=2
would delete the entry corresponding to '[{"name":"George","surname":"Washington"}]';
And the remaining entries would be:
0: "[{\"name\":\"Peter\",\"surname\":\"Brown\"}]"
1: "[{\"name\":\"newname\",\"surname\":\"newsurname\"}]"
3: "[{\"name\":\"John\",\"surname\":\"Adams\"}]"
4: "[{\"name\":\"Thomas\",\"surname\":\"Jefferson\"}]"
Just make a nested array of users:
$data = array (
0 => array("name"=>"Peter","surname"=>"Brown"),
1 => array("name"=>"newname","surname"=>"newsurname")
);
echo json_encode($data);
// [{"name":"Peter","surname":"Brown"},{"name":"newname","surname":"newsurname"}]
I think it would be easiest to store the data in a session, something like this:
<?php
session_start();
if (isset($_GET['name'])) {
$_SESSION['json'][] = $_GET;
}
echo json_encode($_SESSION['json']);
?>
Edit: You may want to filter the $_GET array before storing it in the session so that you don't store values that aren't meant to be stored.
Edit: Of course, if you want to save this data for more than one session you would need to use files or a database (or perhaps a cookie). It all depends on what you want to do with the information.

Categories