[Solved] Parametrizing Select Fields In Criteria For Ar?

I’m building a small API, and would like to allow the requester to specify fields to obtain in the API call.

Something like http://domain.com/api/model?fields=id,name,description

And I would later insert that into a criteria object to use in the AR. Ex:




$criteria=new CDbCriteria();

$criteria->select=$_GET['fields'];


myObj::model()->find($criteria);



The problem with the above is that I could, in theory (I actually did a SELECT COUNT(*) FROM Table and it was injected), SQL inject the fields. Something like:

http://domain.com/api/model?fields=SELECT * FROM USER –

I started to white list the available fields, but it seems so dirty and cluttered that way. I was wondering if there is a way to parametrize the select fields? I tried the following but I just get exceptions “Invalid parameter number: mixed named and positional parameters”. Since the fields and the models are dynamic, I can’t just hard code the parameters.

I was hoping that something like this would work, but no luck:




criteria=new CDbCriteria();

$criteria->condition="id=:Id";

$criteria->select="?,?,?";

$criteria->params=array('test','name','description',':Id'=>$_GET['id']); // replace the first 3 with the actual dynamic fields, $_GET['fields'];



It’s a bit of a hard problem I’m guessing. If possible, I would love to forego the white list checking. Any ideas?

Try getting the attribute names from the model and filter the data from $_GET this way:




$model = new myObj(); // your model

$criteria=new CDbCriteria();

$mycriteria = explode(',', $_GET['fields']; // make array of the input

 $mycriteria = array_intersect($mycriteria, array_keys($model->getAttributes())); // Get the attributes from input which exists in the model

$select = implode(',', $criteria); // make comma separated list for input into query

$criteria->select = $select;

myObj::model()->find($criteria);



Thank you Paul! It seems like a good and cleaner workaround. I will try it and post results later.

I had to reorganize some code, but apparently it worked as expected.




       if(!empty($this->selectFields)){

            $allowedFields=array_intersect($this->selectFields,array_keys($this->model->attributes)); //selectFields are already trimmed

            $criteria->select=$this->selectFields;

        }



Thanks!