Store a PHP array in a single SQL cell - php

I wish to store the ingredients if an item as an array or similar data type in my SQL Database and cannot able to find satisfactory information on the subject
In PHP, the information will get stored as ingredient["$id"]=true or false, where $id represents an ingredient
So for plain bread (please note this is mostly still pseudo code as the data entry side has not yet been started)
//code that creates array this bit is still theory and will be manually emulated in the db for the time being
$id=1;
while (isset ($_POST["ingredient part of form".$ID])){
if ($_POST["ingredient".$id]==checked){
$p["ingredient"][$id]=true;
}
else{
$p["ingredient"][$id]=false
}
$id++;
}
//the code that gets the values back for the ingredient name we will use a separate array ingredient_n[$id]
echo p[$prod_id]["item"].': '
$id=1
while (isset ($ingredient[$id])){
if ($p[$prod_id]["ingredient"][$id]==true)
if ($id!=1){
echo ', ';
}
echo $ingredient_n[$id];
}
}
echo '.';
This should produce something like
'PLAIN BREAD: WHEAT FLOUR, WATER, SALT, YEAST.'
I looked in to ENUM and SET but that would make adding new ingredients harder

Judging by the topic (Store a PHP array in a single SQL cell) you should serialize this. There are standardized methods for that
$array["a"] = "Hello";
$array["b"] = "World";
$array["c"] = "!";
$str = serialize($array);
// The contents of $str
// a:3:{s:1:"a";s:5:"Hello";s:1:"b";s:5:"World";s:1:"c";s:1:"!";}
To reverse use unserialize
$unserializedString = unserialize($str);
You can use this for both arrays and objects.
http://php.net/manual/en/function.serialize.php

I wish to store the ingredients if an item as an array or similar data type in my SQL db an cannot find satisfactory information on the subject
If serialising data is the answer to a database-oriented question, chances are that you're asking the wrong question. Normalise your database, and you'll probably insert the ingredients into a separate table, using a JOIN to retrieve them. This makes your database easier to use, more searchable and more maintainable.
That said; there are cases where storing a serialised string is actually the most viable solution, but this one doesn't seem to be that case.

Related

How to bulk insert with RedBeanPhp?

I was hoping for an example on how to bulk insert new "beans" in readbeanphp without looping over each instance.
It shows an example creating and saving a beans here: http://redbeanphp.com/manual/create_a_bean
It makes mention of storeAll($beans) method, but I am unsure exactly how I am suppose to format the data in $beans.
I have tried googling for this and can not find anything related to bulk inserts. Maybe I have searched for the wrong terms.
I am new to this ORM, any help with would appreciated, thanks!
You are definitely right on track. Create a new bean using $bean=R::dispense('bean'); or multiple beans as an array $beans=R::dispense('bean',5);
Then you populate the beans with data:
$bean->title='Hello World!';
//or with an array
$beans[0]->title='Hello World!';
$beans[1]->title='Hello World! Bean 1';
//etc
Then store the bean(s):
R::store($bean);
//or
R::storeAll($beans);
All the beans must be the same type if you have multiples as far as I know, so you can do something like:
$beans=array();
$beans[]=R::dispense('bean');
$beans[]=R::dispense('bean');
$beans[0]->title='Hello World!';
$beans[1]->title='Hello World!1';
R::storeAll($beans);
I could be wrong about that though. The main thing is that this is all a typical ORM, but redbean also supports regular SQL if you need to use it. Hope that helps!
Some real data behind this approach.
FIRST APPROACH.
foreach item found
$bean = R::dispense('bean');
$bean->title = "hello";
R::store("bean");
time taken for 5660 rows = 43s on my mac
SECOND APPROACH.
$beans=array();
$beans[]=R::dispense('bean');
$beans[]=R::dispense('bean');
$beans[0]->title='Hello World!';
$beans[1]->title='Hello World!1';
R::storeAll($beans);
For 5660 rows, 46s. The storeAll is where all the time is. So its taking ages to store these beans.
THIRD APPROACH
$beans=R::dispense('bean',5560);
for loop
$bean[$i]->title = "hello world";
end for
R::storeAll($beans);
For 5660 rows 45s.
Result. None of these approaches are any quicker. : (
RedBean Transactions didn't seem to make this any quicker either
From the creator of RedBean https://stackoverflow.com/a/18811996/445492 Bulk Insert is not supported, use pure sql.
FOURTH APPROACH
for loop
R::exec("insert into bean(title) values (1,'hello world')");
end for
for 5660 rows 7.3s <----- WOW
(please note: I am actually doing some stuff prior so all these results are -4.3 seconds.)
Hence every bean needs to be created first and the method to create a bean is dispense
$bean = R::dispense('customers');
$bean->name = "John";
R::store($bean);
$bean->name = "Walter"
R::store($bean);
the code above creates only one bean even after storing it. Still $bean refers to the same object, so for each record you have to create a new been by using dispense method.
Luckily we have storeAll method that stores all the beans but it requires an array of beans. So we create a bean in each iteration and push it to the array and then at the end of loop we just pass that array to storeAll function.
//create empty array
$beans = array();
//for each customer post create a new bean as a row/record
foreach ($post as $customer) {
$bean = R::dispense('customers');
//assign column values
$bean->firstName = $customer['first_name'];
$bean->lastName = $customer['last_name'];
//push row to array
$beans[] = $bean;
}
//store the whole array of beans at once
R::storeAll($beans);
In the approaches 1, 2 and 3 suggested by John Ballinger, one way to optimize the run time is to put all the insertions performed by storeAll($beans) inside one database transaction. This could be done as follows: replace the line "R::storeAll($beans)" by the following three lines:
R::begin();
R::storeAll($beans);
R::commit();
This approach reduces dramatically the run time when the array $beans is large, AND is not necessary to use SQL "explicitly".

CodeIgniter MVC data manipulation best approach

I'm developing a website in CodeIgniter. It's kind of basic, except it has some enormous forms (150 fields) some dynamically created/locked/predefined/removed etc..
I'm having trouble doing the transition between the form and the database, which of course is very complicated. What I mean is that the submit of the form inserts more than one line in some tables and some data is not even saved. (some radio buttons etc..)
I have created a very large object with as many properties as possible named after the form input names in order to fill with the $_POST data using:
foreach ($largeObj as $key=>$value)
{
if (isset($_POST[$key])){
$largeObj[$key]=$value; //mind the data escaping
}
}
Of course this only works for half the inputs, for the others I need to do something like this:
$largeObj['tanks']=Array();
for ($i=0;$i<$_POST['nbrTanks'];$i++){
$tank=new Tank();
// some if's in order to set some properties
$largeObj['tanks'][]=$tank;
}
Then I do all the calculations and prepare my DTO's to insert in each table the corresponding data. Btw I used PHPDAO to map the database tables as they were a bit too large to write the entire CRUD operations.
Is there a better approach? something annotation-driven or a more efficient way because I also need to fill the entire forms with the data from my DB. Any suggestions are welcome.
If you have a list of the inputs that go to either method, you can do something like this:
##Array of items to be checked with `isset()`
$array_isset = array('field1', 'field2', 'field3');
foreach ($array_isset as $line) {
#.... same thing you did before
}
$array_tank = array('field4', 'field5', 'field6');
foreach ($array_tank as $line) {
$tank = new Tank()
}
If I understand your question, the above method would allow you to sort the fields by the operations that need to be performed on them.
That being said, I've had multiple projects where I've had to deal with large amounts of information. What I found, every single time, was that the best approach is to find a way to put the raw data in to the database, and perform your calculations at a later date.
This also makes it easy, because in CodeIgniter, you can just do this:
$array = $this->input->post(NULL, True);
$this->db->insert('table', $array);
If your form fields match up with your database column names.
If you have a list of data, then you can store the data as a comma-separted list like this:
$array = array('value1', 'value2', 'value3');
$insert_string = implode(',', $array);
And explode it when you select it.
This may not work in your situation, but it does have value in certain situations.
Good luck with your application; I hope I helped!

PHP Cookies - Stores 2 pieces of data in one cookie

I have 2 pieces of data related to the same topic being country an country code.
eg: Australia and AU
Is there a preferred way to store 2 pieces of data in the one cookie?
Or Better to just use 2 cookies.
Sorry if this is a silly questions... Just interested in other peoples opinions.
thx
If it were me I would just append the data together using a specific glue, then explode the string when I wanted to separate the values again.
$cookeString = $country . '+' . $countryCode;
list($country, $countryCode) = explode('+', $cookieString);
But in all honesty it doesn't make sense to store country and country code, just store country code and look up country data using country code as a key.
Why not use javascript and create a json object ?
var cc = {
australia: 'au',
India : 'In'
}
You can use as cc.India
I know, you asked about cookies, but I needed to store country codes, and I did this way. Its fast and easy.
You can do it a number of ways, either multiple cookies, or storing an Object like JSON, or you could just simply put a string delimited by something like :: for example and user php's eplode function. All in all its a matter of preference and dependent upon what your doing. If you use a JSON object you could easily switch back and forth between the object and an array as well through the use of json_encode and json_decode. Again its all about where your comfort level is. All in all though your looking at working with an array of data in the end if you really want to keep it in a single cookie.
Example:
<?php
//set the cookie
$cookieData = json_encode(array("value_one", "value_two"));
setcookie("MyCookie", $cookieData , time()+3600);
//read the cookie
$cookieInfo = json_decode($_COOKIE['MyCookie']);
echo $cookieInfo[0]."<br>";
echo $cookieInfo[1]."<br>";
//or
for($i = 0; $i < count($cookieInfo); $i++)
{
echo $cookieInfo[$i]."<br>";
}
You can make this concept fairly large, but bare in mind cookies are easily manipulated client side so sanitize your cookie variables before running them through script that can be injected and broken for other needs, example checking a database to see if a use is valid via cookie information.
Another thing to remember is some browsers have a cookie size, you where the max size of a cookie is 4kb only.
Also you can get a little more fancy with the logic of using JSON and Arrays, they are tricky at first if your not familiar with them but once you start using them and understand them, you will find they are your best friends.
You can also set array cookies by using array notation in the cookie name.
PHP Code -
// set the cookies
setcookie("cookie[one]", "cookie1");
setcookie("cookie[two]", "cookie2");
setcookie("cookie[three]", "cookie3");
// after the page reloads, print them out
if (isset($_COOKIE['cookie'])) {
foreach ($_COOKIE['cookie'] as $name => $value) {
$name = htmlspecialchars($name);
$value = htmlspecialchars($value);
echo "$name : $value <br />";
}
}
Output:
one : cookie1
two : cookie2
three : cookie3

An imported array from mysql works, but the array can't be used by php as an array?

The code below won't work because of this line $params=array($data);. It needs something other than $data. Or it needs something to happen with $data prior to this line.
If the line is written as $params=array("A", "B", "C", "D"); then it works great, but my array is in the $data variable, not written out like that. If there is a way to get the array converted to being written out like that, that would work too.
The end result should show every possible combination (not permutation) of the contents of the array. Like in the example above it shows ABC, BD, etc.
$data = mysql_query('SELECT weight FROM my_table WHERE session_id = "' . session_id() . '"');
$params=array($data);
$combinations=getCombinations($params);
function getCombinations($array)
{
$length=sizeof($array);
$combocount=pow(2,$length);
for ($i=1; $i<$combocount; $i++)
{
$binary = str_pad(decbin($i), $length, "0", STR_PAD_LEFT);
$combination='';
for($j=0;$j<$length;$j++)
{
if($binary[$j]=="1")
$combination.=$array[$j];
}
$combinationsarray[]=$combination;
echo $combination."<br>";
}
return $combinationsarray;
}
mysql_query() only returns a result resource ID. To retrieve data, you must use one of the "fetch" commands, for example
$params = array();
while ($row = mysql_fetch_assoc($data)) {
$params[] = $row['weight'];
}
Also, your query is possibly vulnerable to SQL injection. I wouldn't implicitly trust the value from session_id(). I'm not entirely sure of this but it may simply retrieve the value from the session cookie.
At the very least, sanitise the value with mysql_real_escape_string(). A more robust solution which would bring your code out of the dark ages would be to use PDO and parameter binding.
$data is not an array. Assuming mysql_query() did not return an error or an empty result (both of which you should check for, by the way--lookup documentation for mysql_error() and mysql_num_rows() perhaps, maybe some others), $data is a resource.
So you want $params=mysql_fetch_array($data) to make it an array. (That assumes that there is only one result. If it might return more than one row, you'll probably want to wrap it in a loop. If you are 100% certain that session_id is unique , then you can get away without the loop, I suppose. You can also get away without the loop if you only care about the first result in a multi-row result, although I'd throw in a LIMIT 1 in your query in that case to improve performance.)
There are lots of options (do you want a numerically indexed array, or one where they keys are the names of the columns, etc.) so read up at http://www.php.net/manual/en/function.mysql-fetch-array.php.
Ok there are alot of fundamental problems with your script. I personally recommend to first read this article and then about the actual function called mysql_fetch_array().
Simply put, what you are receiving from mysql is resource (corrent me if i'm wrong!) and you have to fetch array on that.
$params = mysql_fetch_array($data);
PS: This makes no sense: $params=array($data);

Most efficient way to get data from the database to session

What is the quickest way to get a large amount of data (think golf) and the most efficient (think performance) to get a large amount of data from a MySQL database to a session without having to continue doing what I already have:
$sql = "SELECT * FROM users WHERE username='" . mysql_escape_string($_POST['username']) . "' AND password='" . mysql_escape_string(md5($_POST['password'])) . "'";
$result = mysql_query($sql, $link) or die("There was an error while trying to get your information.\n<!--\n" . mysql_error($link) . "\n-->");
if(mysql_num_rows($result) < 1)
{
$_SESSION['username'] = $_POST['username'];
redirect('index.php?p=signup');
}
$_SESSION['id'] = mysql_result($result, '0', 'id');
$_SESSION['fName'] = mysql_result($result, '0', 'fName');
$_SESSION['lName'] = mysql_result($result, '0', 'lName');
...
And before anyone asks yes I do really need to 'SELECT
Edit: Yes, I am sanitizing the data, so that there can be no SQL injection, that is further up in the code.
I came up with this and it appears to work.
while($row = mysql_fetch_assoc($result))
{
$_SESSION = array_merge_recursive($_SESSION, $row);
}
Most efficient:
$get = mysql_query("SELECT * FROM table_name WHERE field_name=$something") or die(mysql_error());
$_SESSION['data'] = mysql_fetch_assoc($get);
Done.
This is now stored in an array. So say a field is username you just do:
echo $_SESSION['data']['username'];
Data is the name of the array - username is the array field.. which holds the value for that field.
EDIT: fixed some syntax mistakes :P but you get the idea.
OK, this doesn't answer your question, but doesn't your current code leave you open to SQL Injection?
I could be wrong, never worked in PHP, just saw the use of strings in the SQL and alarm bells started ringing!
Edit:
I am not trying to tamper with your post, I was correcting a spelling error, please do not roll back.
I am not sure what you mean by "large amounts of data", but it looks to me like you are only initializing data for one user? If so, I don't see any reason to optimize this unless you have hundreds of columns in your database with several megabytes of data in them.
Or, to put it differently, why do you need to optimize this? Are you having performance problems?
What you are doing now is the straight-forward approach, and I can't really see any reason to do it differently unless you have some specific problems with it.
Wrapping the user data in a user object might help some on the program structure though. Validating your input is probably also a good idea.
#Unkwntech
Looks like you are correct, but following a Google, which led here looks like you may want to change to mysql_real_escape_string()
As for the edit, I corrected the spelling of efficient as well as removed the "what is the".. Since that's not really required since the topic says it all.
You can review the edit history (which nicely highlights the actual changes) by clicking the "edited a min ago" text at the bottom of your question.
Try using json for example:
$_SESSION['data'] = json_encode(mysql_fetch_array($result));
Is the implementation of that function faster than what he is already doing?
Does anyone else have trouble entering ] into markdown? I have to paste it in
Yes, it's bugged.
#Anders - there are something like 50-75 columns.
Again, unless this is actually causing performance problems in your application I would not bother with optimizing it. If, however, performance is a problem I would consider only getting some of the data initially and lazy-loading the other columns as they are needed.
If Unkwntech's suggestion does indeed work, I suggest you change your SELECT statement so that it doesn't grab everything, since your password column would be one of those fields.
As for whether or not you need to keep this stuff in the session, I say why not? If you're going to check the DB when the user logs in (I'm assuming this would be done then, no?) anyway, you might as well store fairly non-sensitive information (like name) in the session if you plan on using that information throughout the person's visit.
It's not so much that it causing performance problems but that I would like the code to look a bit cleaner.
Then wrap the user data in a class. Modifyng $_SESSION directly looks somewhat dirty. If you want to keep the data in a dictionary—which you can still do even if you put it in a separate class.
You could also implement a loop that iterates over all columns, gets their names and copy the data to a map with the same key names. That way your internal variables—named by key in the dictionary—and database column names would always be the same. (This also has the downside of changing the variable name when you change the column name in the database, but this is a quite common and well-accepted trade-off.)
Try using json for example:
$_SESSION['data'] = json_encode(mysql_fetch_array($result));
Edit
Later you then json_decode the $_SESSION['data'] variable and you got an array with all the data you need.
Clarification:
You can use json_encode and json_decode if you want to reduce the number of lines of code you write. In the example in the question, a line of code was needed to copy each column in the database to the SESSION array. Instead of doing it with 50-75 lines of code, you could do it with 1 by json_encoding the entire database record into a string. This string can be stored in the SESSION variable. Later, when the user visits another page, the SESSION variable is there with the entire JSON string. If you then want to know the first name, you can use the following code:
$fname = json_decode($_SESSION['data'])['fname'];
This method won't be faster than a line by line copy, but it will save coding and it will be more resistant to changes in your database or code.
BTW
Does anyone else have trouble entering ] into markdown? I have to paste it in.

Categories