Selecting a table with multiple ID on MySQL using PHP PDO I have made a MySQL script to query a table with a set of id using an IN clause and after some reading I found out that there are security issues with it like prone to SQL injections and the likes.

Are there other ways to write this code with a more secure way? Although I'm using PDO, is that really enough?

 public function GetAllCustomerFilter($search, $cat_id)
 {    
   $stmt = $this-&gt;db-&gt;prepare("SELECT * from users_cards WHERE cat_id IN ($cat_id) AND username LIKE :search ORDER BY id DESC LIMIT 60";
   $stmt-&gt;bindParam(":search", $search);
     if($stmt-&gt;execute()) {
       $products =  $stmt-&gt;fetchAll(PDO::FETCH_ASSOC);
     }
 }


Data is received from an Ajax:

    loadProductsListPerCat = function(form,data_serve) {

    var data_fed = new Array();
    $.each(data_serve, function(i,obj)
    {
        data_fed[i] = obj.cat_id;
    });
    var raw = data_fed.join();
    var encoded = encodeURIComponent(raw);
    var formData =  "data_serve="+encoded+"&amp;"+ $(form).serialize(); 
    var requestURL = 'searchUsers';
    console.log(formData);
    $.ajax({
        url: requestURL,
        data: formData,
        crossDomain: true,
        dataType: 'json',
        cached: false,
        async: true,
        success: function(data) {
            console.log(data);

        },
        complete: function() {
            if(isAppend) {
                $('.btn-toggle-load-more-users').attr('disabled', false);
            }
        },
        error: function(XMLHttpRequest, textStatus, errorThrown) {

        }
    });    
};


The variable data_serve is taken by another jQuery function on which it counts input elements that has data-on set to true:

var PCatVal = (function(){
    var cats = new Array();

    $("#main_cat").find(".option_").each(function(index) {
        $(this).removeClass("option_");
        $(this).addClass("ctrls option_"+index);

        $(".option_"+index).on("click", function(e){
            var opt = $(this).data('parentname');
            var opt_id = $(this).val();
            var data_serve = [];
            //array check if exists
            var idx = $.inArray(opt_id, cats);
                if (idx == -1) {
                   cats.push(opt_id);  
                } else {
                    cats.splice(idx, 1);
                }
           //loop the array so to encode to a json format
            $.each(cats, function(i,obj){
              data_serve.push({"cat_id": obj});
            });
            //Switch for the category buttons
            var swtch_var = $(this).attr('data-on');

                if(swtch_var == 0)
                {
                  swtch_var = 1;
                }
                else
                {
                  swtch_var = 0;
                }
                $(this).attr('data-on',swtch_var);  

loadUsers($('#frmSearchUsers'),'',data_serve);


           e.preventDefault();
        });
    });
});


This is how the $_GET parameters are received:

    public function searchUser() 
    {
     $cat_id = (isset($_GET['data_serve']) &amp;&amp; !empty($_GET['data_serve'])) ? $_GET['data_serve'] : null;
$search_filter = (isset($_GET['search_filter']) &amp;&amp; !empty($_GET['search_filter'])) ? $_GET['search_filter'] : null;

     $products = $this-&gt;model-&gt;GetAllCustomerFilter($search_filter, $cat_id);
    return $products;
    }
When I changed from the mysqli_functions to PDO with prepared statements, I had the same question. I found the answers to this question to be very usefull: https://stackoverflow.com/questions/134099/are-pdo-prepared-statements-sufficient-to-prevent-sql-injection.

Let's say you have messaging functionality and someone types SQL injection code in the title field when sending a message. You use a prepared statement, and the SQL injection code gets saved as the title. the SQL injection code didn't get executed, you have been saved from 1st order SQL injection.

Now let's say you have a function to reply to messages that uses the previous message title and adds "RE: " before it. If this reply function assumes the new title is safe since it's not coming from a user input field and doesn't use a prepared statement on the reply title, the SQL injection code will get executed. This is called 2nd order SQL injection.

You're 1st order safe if you use prepared statements for queries requiring user input. You're 2nd order safe if you use prepared statements for every query.