Mysql Insert PHP colons, semi colons and double quotes - php

i am writing a custom script to insert data into a wordpress database. The database contains an address section and the data in the field has various colons, semi colons and double quotes. I am having a hard time trying to write the php mysql insert statement. Getting a lot of syntax errors.
The Field looks like:
a:9:{s:8:"address1";s:7:"street1";s:8:"address2";s:7:"street2";s:4:"city";s:9:"London";s:5:"state";s:5:"Bucks";s:11:"postal_code";s:8:"MK49 8UY";s:7:"country";s:2:"GB";s:13:"logo_image_id";s:1:"0";s:5:"notes";s:0:"";s:12:"instructions";s:0:"";}
Can anyone offer any guidance on how to escape such a large number of characters

As Roberto Suggests - if you are attempting to insert a pre formatted serialized array into your database (and it has an error) it's not going to work. If you are collecting all the data individually and building it the simpler way to go about this would be to first construct the array, then convert it to a format that can be stored in the database easily (serialised arrays). Example:
$address = array(
'address1' => 'Street1',
'address2' => 'Street2',
'city' => 'London',
'state' => 'bucks',
'postal_code' => 'MK49 8UY',
'country' => 'GB',
);
$formattedAddress = serialize($address);
// returns
// a:6:{s:8:"address1";s:7:"Street1";s:8:"address2";s:7:"Street2";s:4:"city";s:6:"London";s:5:"state";s:5:"bucks";s:11:"postal_code";s:8:"MK49 8UY";s:7:"country";s:2:"GB";}
You can now reference $address within your insert statement to get a correctly formatted serialized array.

Related

Preparing a SQL statement that contains paired single and double quotes in PHP

Here goes. I have a 200-line MySQL query that contains six different Excel formulas in one of the columns, like this:
SELECT '%%%=""Greg''s #""&INDIRECT(""G""&ROW()&""#"")' AS 'Location'
This code snippet will run correctly in MySQL, and because of the doubled-up punctuation, can be exported to a CSV without causing havoc in the CSV. However, now I have to put this query into a prepared statement in PHP as part of the process of automating my company's (you guessed it, Excel-based) reporting. How do I harden the prepared statement against all the doubled punctuation?
I've tried escaping with a \ before each quotation mark, but this somehow causes the MySQL query to return only the Excel formulas, and not the database data that has to go alongside it. Same with heredoc. PDO::quote() didn't even get me that far. I half suspect there's a way to use fputcsv to get around the problem, but I assume I have to prepare the statement before bringing fputcsv into the fray. (Not saying I've done any of these the correct way; I'm trying whatever Google says to try at this point.) So far, no queries have returned in PHP what they do in SQL.
The various data I care about exist in all three formats (and more besides...), and have to be collected as I go downstream, in this case from PHP to MySQL to an emailed CSV to a VBA-automated Excel report. My company thinks of data storage solutions like Pokémon. Gotta subscribe to them all. So this is a problem I can't just dodge.
Thank you, kind people. I'm doing my utmost to get our reporting under control, but this challenge has so far proved un-Googleable (probably because Google doesn't understand "double double quotes" or "paired double quotes").
HEREDOC does the trick. The following code does not get mangled:
$csv_fields = array("Location","Location ID","Region","Area","Area #","Client","Store #","Signature","AM","AR","AA");
$TechExport = <<<Your_HEREDOC_Tag
SELECT
a.location AS 'Location'
, '%%%=FILTER(''Store Admin''!A:A,(''Store Admin''!A:A<>''Store Admin''!A1)*(''Store Admin''!A:A<>""))' AS 'Location ID'
, '%%%=INDEX(''Store Admin''!B:B,XMATCH(INDIRECT("B"&ROW()&"#"),''Store Admin''!G:G))' AS 'Region'
, '%%%=INDEX(''Store Admin''!C:C,XMATCH(INDIRECT("B"&ROW()&"#"),''Store Admin''!G:G))' AS 'Area'
, '%%%=INDEX(''Store Admin''!D:D,XMATCH(INDIRECT("B"&ROW()&"#"),''Store Admin''!G:G))' AS 'Area #'
, '%%%=INDEX(''Store Admin''!E:E,XMATCH(INDIRECT("B"&ROW()&"#"),''Store Admin''!G:G))' AS 'Client'
, '%%%=INDEX(''Store Admin''!F:F,XMATCH(INDIRECT("B"&ROW()&"#"),''Store Admin''!G:G))' AS 'Store #'
, '%%%=FILTER(UNIQUE(FILTER(SORTBY(FILTER(''Requests''!I:M,(ISNUMBER(''Requests''!F:F))),FILTER(''Requests''!F:F,(ISNUMBER(''Requests''!F:F)))),{1,0,0,0,1})),{0,1})' AS 'Signature'
, '%%%=INDEX(''Store Admin''!P:P,XMATCH(INDIRECT("B"&ROW()&"#"),''Store Admin''!G:G))' AS 'AM'
, '%%%=SUMIFS(''Requests''!H:H,''Requests''!M:M,INDIRECT("B"&ROW()&"#"),''Requests''!I:I,INDIRECT("S"&ROW()&"#"))' AS 'AR'
, '%%%=SUMIFS(''Assembly''!F:F,''Assembly''!A:A,INDIRECT("B"&ROW()&"#"),''Assembly''!E:E,INDIRECT("S"&ROW()&"#"))' AS 'AA'
FROM
`full-database-name`.location a;
Your_HEREDOC_Tag;
$preparedSQL = $db->prepare($SQL);
$preparedSQL->execute();
$results = $preparedSQL->fetchAll(PDO::FETCH_ASSOC);
$f = fopen('./test/Results.csv', 'w+');
fputcsv($f,$csv_fields);
foreach ($results as $result)
{
fputcsv($f,$result);
}
fclose($f);
I needed to do three things to convert my SQL code to a prepared statement:
First, put the HEREDOC tag around the entire SQL code block.
Second, fully qualify the SQL table references.
Third, turn the paired double quotes into normal double quotes (""this"" into "this"). Single quotes stay paired (''like this''). I assume this is the fputcsv function preserving the double quotes during the CSV creation, where in MySQL I had to preserve them by doubling them up, but honestly this is just a guess.

Query Exception when creating a database record using laravel eloquent

I am encountering a weird error.
In a laravel project I am reading a CSV file. In my Controller I am parsing the CSV and creating database records for a mysql database.
I convert the CSV lines into individual arrays which are located within a big array -> two dimensional array. So far so good.
When iterating through my array the first iteration works just fine and I get the database records as expected. However, during the second iteration a Query Exception is thrown.
The stack trace leads me to a line where I am assigning a double value to an attribute of the model.
Transaction::firstOrCreate([
'date' => $date,
'transaction_type' => $the_big_array[$i][2],
'db_counter_party_id' => $db_counter_party_id,
'amount' => $amount,
'currency' => $the_big_array[$i][6],
'usage' => $the_big_array[$i][7],
'category' => "none",
'balance' => $balance_after_transaction,
]);
The last assignment is causing the error. The variable balance_after_transaction is of type double and calculated according to previous transactions. So it is not directly retrieved from the CSV.
Does someone have a clue what is going on?
The error was caused by a wrong character encoding.

How to insert Array to Database using firstOrCreate in Laravel?

I have an array like this and it has 120 elements in it
`array (size=120)
0 =>
array (size=8)
'name' => That the quick brown fox jumps over the lazy - 7' (length=53)
'url' => string 'google.com/zyx' (length=134)
'category' => string 'search-engine' (length=6)
1 =>
array (size=8)
'name' => string 'Mr. john brandy gave me a wall nut of quite' (length=67)
'url' => string 'yahoo.com/dzxser' (length=166)
'category' => string 'indian' (length=6)`
I want to insert them to my bookmark table which model I have created and I want to make sure duplication doesn't occur. I have found this https://laravel.com/docs/5.4/eloquent#other-creation-methods specially firstOrCreate method.
I assume I have to use foreach but I am not sure how. Can anyone help me with some workaround.
Actually you don't need firstOrCreate, you need updateOrCreate. Checking Laravel Other Creation methods You will find that method.
Say that array is in $alldata:
foreach($alldata as $data) {
MyModel::updateOrCreate($data); //the fields must be fillable in the model
}
This will run update/or create of 120 queries while cycling through the loop. The advantage is that, you cannot have a duplicate, rather if there is a repetition, its only going to perform an update to the table.
However the best way to ensure that there is no duplication in whatever way the data comes is to set it up when making your database table. You can set unique constraints on many fields if thats your case.
If you don't want duplication to occur when inserting array of records then all you have to do it set a constraint making sure fields are unique.
If you're using migrations to create databse schema you can use something like this: $table->string('name')->unique();
Now for example, this will make sure that 'name' column data is

mysql postcode search

Evening All.
I have a mysql database for a property website. There is a search form where people can enter a location or postcode in the same field.
Part of the SQL is
PostCode LIKE '$Loc%
Put my problem is some people enter a post code like this : "l236yt" and some with a space like this "l23 6yt".
The database contains the postcodes with the space in them so how can make it work with or without the space ??
Any help will be greatly appreciated
thanks baz
Assuming the values in your database are without space, just sanitize the user value to a value without space:
$val = str_replace(' ', '', $val);
You could convert the string into an array of characters, and search for spaces, if you don't find any, you can then proceed to insert a space (the space will always be after the third character in a 6 character postcode, and after the fourth character in a 7 character postcode, so you can use regex to do this quite simply. I believe there are also postcodes which are 5 characters long, and these will be like A1 1AA, so after the second character you'll find the space.
I can't help with precise code due to my lack of knowledge of the language, but good luck!
Expects a valid postcode as input (with or without spaces), and breaks it down into constituent parts as well as returning it neatly formatted with a space in the appropriate place
function parsePostcode($postcode) {
$postcode = preg_replace('/\s*/','',strtoupper($postcode));
$sector = substr($postcode,0,-2);
$outcode = $district = substr($sector,0,-1);
list($area) = sscanf($district,'%[A-Z]');
$incode = substr($postcode,-3);
return array(
'postcode' => $postcode,
'formatted' => $outcode.' '.$incode,
'area' => $area,
'district' => $district,
'sector' => $sector,
'outcode' => $outcode,
'incode' => $incode,
);
}
Your first priority is to remove the LIKE condition from your query. Using LIKE conditions forces MySQL to evaluate every row in your table and is very inefficient. Try to avoid using a LIKE unless absolutely necessary. In order to change this part of your query, you will need to replace it with:
PostCode = "$Loc"
This presents you with two options:
1) sanitise your input. Postcodes follow a well known format so it is possible to convert the value that someone enters into something you expect. You can then search on. As $Loc would match exactly what you have in the database, it would be very fast to find in your database (provided you have indexed the field of course!).
2) overload the database with multiple values to represent the same postcode. This would mean that you would put both "l236yt" and "l23 6yt" in the database and handle them as if they are different values. This also helps when you want to search on just the first part of the postcode, such as "l23", but would only work if you have a one-to-many relationship between postcodes and locations.

How to do OR search

I want to search for a partial first and last name match - for example in sql
f_name LIKE J% OR l_name LIKE S%
would match John Smith or John Henry or Harry Smith .
I am assuming I may need to use the "$or" operator,
I have this so far that I believe is doing the LIKE % part properly, but I believe it is doing an "AND" search (meaning it searches for f_name LIKE J% AND l_name LIKE S% so it would only match John Smith):
$name1="J";
$name2="S";
$cursor = $this->clientCollection->find(array('f_name' => new MongoRegex('/^'.$name1.'/i'), 'l_name' => new MongoRegex('/^'.$name2.'/i') ));
Note: This will match containing as in %J%
MongoRegex('/'.$name1.'/i')
This will match starts with (notice the added ^) as in J%
MongoRegex('/^'.$name1.'/i')
$or takes an array of clauses, so you basically just need to wrap another array around your current query:
array('$or' => array(
array('f_name' => new MongoRegex('/'.$name1.'/i')),
array('l_name' => new MongoRegex('/'.$name2.'/i'))
));
Edit: the previous example missed an inner set of array() calls.
The original, wrong, example that I posted looked like this:
array('$or' => array(
'f_name' => new MongoRegex('/'.$name1.'/i'),
'l_name' => new MongoRegex('/'.$name2.'/i')
));
This is a valid query, but not a useful one. Essentially, the f_name and l_name query parts are still ANDed together, so the $or part is useless (it's only getting passed one query, so it's the same as just running that query by itself).
As for the alternative you mentioned in your comment, that one doesn't work because the outermost array in a query has to be an associative array. The confusion arises because Mongo's query syntax is JSON-like and uses a mixture of objects and arrays, but both of those structures are represented in PHP by arrays. The PHP Mongo driver basically converts PHP associative arrays to JSON objects ({ ... }), and "normal" PHP arrays to JSON arrays ([ ... ]).
The practical upshot is that "normal" PHP arrays are generally only valid when inside an associative array, like when specifying multiple values for a field. The following example from the PHP Mongo manual shows a valid usage of a "normal" array in a query:
$cursor = $collection->find(array("awards" => array('$in' => array("gold", "copper"))));

Categories