1

I'm trying to run the following raw query from Laravel:

DB::statement(
    DB::raw("
    SET @lon = ?;
    SET @lat = ?;
    "),
    [$longitude, $latitude],
);
$places = DB::select(
    DB::raw("
    SELECT
    id
    FROM places
    WHERE
          position = POINT(@lon, @lat)
    AND
          language = ?
    AND
          LOWER(name) LIKE LOWER(CONCAT(?, '%'))
    ORDER BY distance
    LIMIT 10;
    "),
    [
        $language,
        $name,
    ],
);

The actual query is more complex but it's beyond the scope of the question. Suffice to say that I need @lon and @lat to be SQL variables.

This gives me the following error:

SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SET @lat = ?' at line 2 (SQL: \n SET @lon = 7.4653;\n SET @lat = 51.5136;\n )

I had initially tried to put the SET statements inside the same string as the query, but some answers on stack overflow suggested they should be separated. Unfortunately that didn't work, but as far as I can see there isn't any actual error in the syntax, so what is going on?

2
  • what is you MySQL version pls ? Commented May 28, 2021 at 12:26
  • @HichamO-Sfh 5.7.31. Commented May 28, 2021 at 12:28

1 Answer 1

1

According to Laravel Official Documentation, DB:raw doesn't prevent SQL injection attack so it's not the recommended way what to use it in your case even if you're using SQL parameters/variables...
However I think that neither DB::statement nor DB::raw does not support multiple queries, so you should separate them :

// still a 'risky code' :
DB::statement(DB::raw("SET @lon = ?;",[$longitude]));
DB::statement(DB::raw("SET @lat = ?;",[$latitude]));

Still the best practice is to use named bindings


Edit
If you still really need to use DB::raw and DB::statement , then here is a really secured way to use them (combining them with the named binding method ) :

// safe code (said by Laravel) :
DB::statement(DB::raw("SET @lon = :longitude;"), ['longitude'=>$longitude]);
DB::statement(DB::raw("SET @lat = :latitude;"), ['latitude'=>$latitude]);
Sign up to request clarification or add additional context in comments.

9 Comments

Noted. Is there an easy way to secure the query then?
yes of course as I've already said, the best practice is to use prepared parameters & named bindings, I've posted direct links to the documentation. glad to help you.
I have replaced my bindings to be named, but is that enough to prevent SQL injection if $longitude and $latitude come from the request?
@theberzi I'm not really sur about that, but I have already seen something related to preventing SQLi even when using DB::raw : laracasts.com/discuss/channels/laravel/…
@theberzi I have updated my answer, take a look pls.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.