2

I have an Array named $items that looks like the following:

array   (
            0 => '{"id":"1", "qty":"1", "price":"12.51"}',
            1 => '{"id":"2", "qty":"2", "price":"25.02"}',
        )

I'm trying to build a mySQL INSERT statement which includes the data in $items as follows:

$sql = 'INSERT INTO vals (id, items, timestamp) 
        VALUES (' . $id . ', "' . json_encode($items) . '", "' . date('Y-m-d H:i:s')  . '")';

However, the INSERT into mySQL is failing due to json_encode() adding double-quotes around the Array Elements:

INSERT INTO
            vals
                    (
                        id,
                        items,
                        timestamp
                    )
        VALUES
                    (
                        1,
                        "[
                            "{\"id\":\"1\", \"qty\":\"1\", \"price\":\"12.51\"}",
                            "{\"id\":\"2\", \"qty\":\"2\", \"price\":\"25.02\"}"
                        ]",
                        "2015-11-26 20:31:02"
                    )  

It's the double-quotes before/after the curly-braces "{ ...data... }" that are the problem.

Is there a way to convert the Array to a String that will elimnate these extra quotes?

Thanks much for any guidance!

EDIT:

From the examples below, I'm trying to use mysqli prepared statements.

I'm executing the following:

$stmt->bind_param("i", (int) $id)

and am getting this error:

ERROR: exception 'Symfony\Component\Debug\Exception\FatalErrorException' 
with message 'Call to a member function bind_param() on a non-object'

I didn't get an error executing the following:

$stmt = $mysqli->prepare($sql)

so I'm thinking $stmt should be okay to call bind_param() on.

I looked at the PHP docs and don't believe I need to do anything else with $stmt. Does anyone see something I'm missing?

RobertFrenette
  • 629
  • 3
  • 8
  • 29
  • 2
    This is a perfect example of why you should be using prepared statements and parameterized queries - http://stackoverflow.com/a/60496/689579 – Sean Nov 26 '15 at 20:50
  • 2
    Your input array contains json formatted strings so you are json encoding an array of already json encoded items. Decode the original array items first and then encode the entire array. – Josh J Nov 26 '15 at 21:13
  • 1
    use the predefined functions for the extensions that you are using to escape the characters. ie, you can use **mysql_real_escape_string** in case you are using the mysql extension. Look at my answer – Nelson Owalo Nov 26 '15 at 21:30
  • Ahh, so in Symfony, you may need to use the "$stmt->bindParam(":varname",$var);" syntax... see http://php.net/manual/en/class.pdostatement.php and http://php.net/manual/en/pdostatement.bindparam.php – doublehelix Nov 27 '15 at 04:28
  • Got it working using your PDO example. Thanks so much for sticking with me on this - very much appreciated! – RobertFrenette Nov 27 '15 at 13:31

3 Answers3

3

You either need to escape your json_encode'd string for use in the query, or use a prepared statement and bind the value to a parameter.

Your quotes around the individual array items are actually required as your individual array items are in fact strings... so all you need is to escape the entire value...

So either:

$sql = 'INSERT INTO vals (id, items, timestamp)
        VALUES (' . $id . ', "' . mysql_real_escape_string(json_encode($items)) . '", "' . date('Y-m-d H:i:s')  . '")';

or a better way of doing this:

$json = json_encode($items);
$sql = 'INSERT INTO vals (id, items, timestamp) VALUES (?, ?, ?)';

/* Prepared statement, stage 1: prepare */
if (!($stmt = $mysqli->prepare($sql))) {
    echo "Prepare failed: (" . $mysqli->errno . ") " . $mysqli->error;
}

/* Prepared statement, stage 2: bind and execute */
if (!$stmt->bind_param("i", $id)) {
    echo "Binding parameters failed: (" . $stmt->errno . ") " . $stmt->error;
}
if (!$stmt->bind_param("s", $json)) {
    echo "Binding parameters failed: (" . $stmt->errno . ") " . $stmt->error;
}
if (!$stmt->bind_param("s", date('Y-m-d H:i:s'))) {
    echo "Binding parameters failed: (" . $stmt->errno . ") " . $stmt->error;
}

if (!$stmt->execute()) {
    echo "Execute failed: (" . $stmt->errno . ") " . $stmt->error;
}

EDIT

Also, @JoshJ is correct about your values being JSON strings... re-encoding a Json string will double escape everything. If this is not your intended use (i.e. retrieving the values as strings), then you should in fact try decoding each string to an associative array using:

foreach ($items as $key => $item) {
    $items[$key] = json_decode($item, true);
}

This will give you an $items value of:

[
    0 => [
        "id" => "1",
        "qty" => "1",
        "price" => :"12.51"
    ],
    1 => [
        "id" => "2",
        "qty" => "2",
        "price" => "25.02"
    ]
]

There are other options of course for treating numeric string s as numbers in the output which you may also want to investigate...

See: http://php.net/manual/en/function.json-decode.php

EDIT 2 In Symfony, you may need to use the PDO bindParam() function syntax.

$sql = 'INSERT INTO vals (id, items, timestamp) VALUES (:id, :items, :datetime)';
$stmt = $pdoconnection->prepare($sql);
$stmt->bindParam(':id', $id);
etc...

See: http://php.net/manual/en/pdostatement.bindparam.php and http://php.net/manual/en/class.pdostatement.php

doublehelix
  • 2,302
  • 2
  • 18
  • 15
0

Note that from PHP 5.3.3 on, there's a flag for auto-converting numbers, while options parameter was added since PHP 5.3.0:

$arr = array( 'row_id' => '1', 'name' => 'George' );
echo json_encode( $arr, JSON_NUMERIC_CHECK ); // {"row_id":1,"name":"George"}
Pedram marandi
  • 1,474
  • 1
  • 19
  • 35
0

The simplest and safest answer for this is to switch to prepared statements. Documentation for that can be found here

If that doesnt work right with you, you can use simple built in methods for escaping characters.

If you are using MYSQL, you can make use of the mysql_real_escape_string function — It escapes special characters in a string for use in an SQL statement.

Be carefull, as this extension (MYSQL) was deprecated in PHP 5.5.0, and it was removed in PHP 7.0.0.

for MYSQLi, use mysqli::real_escape_string

A use case for your scenarial, i assume you are using the mysql extension:

$sql = 'INSERT INTO vals (id, items, timestamp) VALUES (' . $id . ', "' .mysql_real_escape_string(json_encode($items)). '", "' . date('Y-m-d H:i:s')  . '")';

You can even use php's addslaches() function documented here. What it does is that it: returns a string with backslashes before characters that need to be escaped. These characters are single quote ('), double quote ("), backslash () and NUL (the NULL byte).

Nelson Owalo
  • 2,324
  • 18
  • 37
  • i don't know why the down vote mate, explanation looks valid to me – Nelson Owalo Nov 26 '15 at 21:39
  • 1
    This is bad advice. If you give someone a loaded gun, no matter how many times you warn them not to, someone's going to shoot themselves with it. Also it doesn't address the root of the problem, which is a misunderstanding of how to use `json_encode()` – miken32 Nov 26 '15 at 21:43
  • you cant force someone to switch to prepared statements just like that. It takes time. Id rather give them an aswer that works with what they currently have and give them the downfalls of that method. That way, they can decide for themselves and look into it. If they feel like killing themselves, it's their choice, the'll learn from it. – Nelson Owalo Nov 26 '15 at 21:52
  • @miken32 - json_encode converts the array to string, he knows how to use it **if thats the way he was using it – Nelson Owalo Nov 26 '15 at 21:55
  • Thanks for the suggestions / examples. I'm working through this now and will keep you all posted. – RobertFrenette Nov 26 '15 at 23:59