how to make secure condition in joined Table?

The code above will create the query as displayed at the end of this posting.




$result = $this->findAllByAttributes(

	array('parent'=>$tree['this']->name,/* 'childs.name'=>'test'*/),

            array(

		'with' => 'childs',

		//'condition' => "t.parent = '{$tree['this']->name}'",

		'order' => 'childs.name',

	)

);



But if I try to search in the joined Table, I get an Collumn childs.name does not exist error:





// this results in a Collumn childs.name does not exist error

$result = $this->findAllByAttributes(

	array('parent'=>$tree['this']->name,'childs.name'=>'test'),

        array(

		'with' => 'childs',

		//'condition' => "t.parent = '{$tree['this']->name}'",

		'order' => 'childs.name',

	)

);



The next works, but if $tree[‘this’]->name has a value like testname"'´`

it will destroy the query and is absolutely unsecure.





// this query is absolutely unsecure: ...MySQL Error:"for the right syntax to use near '"´`'..."

// $tree['this']->name will not be escaped

$result = $this->findAll(

	array(

		'with' => 'childs',

		'condition' => "t.parent = '{$tree['this']->name}'",

		'order' => 'childs.name',

	)

);



How can I make a secure condition in a joined Table?

Here ist the Yii generated query from the first try:


/*

	 * SELECT 

	 * 	`t`.`parent` AS `t0_c0`, 

	 * 	`t`.`child` AS `t0_c1`, 

	 * 	`childs`.`name` AS `t1_c0`, 

	 * 	`childs`.`type` AS `t1_c1`, 

	 * 	`childs`.`description` AS `t1_c2`, 

	 * 	`childs`.`bizrule` AS `t1_c3`, 

	 * 	`childs`.`data` AS `t1_c4` 

	 * FROM `AuthItemChild` `t`  

	 * LEFT OUTER JOIN `AuthItem` `childs` 

	 * 	ON (`t`.`child`=`childs`.`name`)  

	 * WHERE (`t`.`parent`=:yp0) 

	 * ORDER BY childs.name

	 */

	

Didn’t fully understand what you try to do. But the right alias for the table should probably be “name” not “childs.name” in the ORDER BY clause.

Ok, here the full method, that works fine at all but…:


     /**

     * 

     * @desc recursive method that generates an Array with the complete RBAC Tree

     * @param array $tree Part of or empty array as main RBAC Tree container

     * @param integer $depth the Tree depth, which is needed only for the debug Renderer

     * @return array with RBAC AuthItem Tree

     * 

     */              

    private function _buildItemTree($tree, $depth)

    {    

        if(count($tree) < 1)

        {

            /*

             * find the Top Level Items with its childs

             * 

             * SELECT 

             *         `t`.`parent` AS `t0_c0`, 

             *         `t`.`parent` AS `t0_c0`, 

             *         `t`.`child` AS `t0_c1`, 

             *         `parents`.`parent` AS `t1_c0`, 

             *         `parents`.`child` AS `t1_c1`, 

             *         `items`.`name` AS `t2_c0`, 

             *         `items`.`type` AS `t2_c1`, 

             *         `items`.`description` AS `t2_c2`, 

             *         `items`.`bizrule` AS `t2_c3`, 

             *         `items`.`data` AS `t2_c4` 

             * FROM `AuthItemChild` `t`  

             * LEFT OUTER JOIN `AuthItemChild` `parents` 

             *         ON (`parents`.`child`=`t`.`parent`)  

             * LEFT OUTER JOIN `AuthItem` `items` 

             *         ON (`t`.`child`=`items`.`name`)  

             * WHERE (parents.parent IS NULL) 

             * ORDER BY t.parent

            */

            $result = $this->findAll(array(

                'with' => array('parents', 'childs'),

                'condition' => 'parents.parent IS NULL',

                'order' => 'parents.parent DESC'

                )

            );

            $depth++;

            $tree['depth'] = 0;

            $tree['parent-name'] = null;

            $tree['this-name'] = null;

            $tree['this'] = null;

            $tree['childs'] = array();

            $modelAuthItem = new AuthItem();

            foreach($result as $row)

            {

                $cnt = count($tree['childs']) - 1;

                if(isset($tree['childs'][0]) && $tree['childs'][$cnt]['this-name'] == $row->parent)

                {

                    // build second depth in existing first depth

                    $tree['childs'][$cnt]['childs'][] = $this->_buildItemTree(array(

                                    'depth' => $depth + 1,

                                    'parent-name' => $row->parent,

                                    'this-name' => $row->childs->name,

                                    'this' => $row->childs,

                                    'childs' => array()), $depth + 1

                                    );

                }else{

                    // build new first depth and included second depth

                    $tree['childs'][] = array(

                                'depth' => $depth,

                                'parent-name' => null,

                                'this-name' => $row->parent,

                                'this' => $modelAuthItem->findByAttributes(array('name'=>$row->parent)),

                                'childs' => array($this->_buildItemTree(array(

                                    'depth' => $depth + 1,

                                    'parent-name' => $row->parent,

                                    'this-name' => $row->childs->name,

                                    'this' => $row->childs,

                                    'childs' => array()), $depth + 1)

                                    )

                                );

                }

            }

            // add unbound items

            $model = new AuthItem();

            $unboundItems = $model->findUnboundItems();

            foreach($unboundItems as $item)

            {

                $child = array(

                    'depth' => 1, 

                    'parent-name' => null, 

                    'this-name' => $item->name,

                    'this' => $item,

                    'childs' => array(),

                );

                array_unshift($tree['childs'], $child);

            }

            return $tree;

        }else{

            /* find Childs from current parent with its AuthItem object

             * SELECT 

             *         `t`.`parent` AS `t0_c0`, 

             *         `t`.`child` AS `t0_c1`, 

             *         `childs`.`name` AS `t1_c0`, 

             *         `childs`.`type` AS `t1_c1`, 

             *         `childs`.`description` AS `t1_c2`, 

             *         `childs`.`bizrule` AS `t1_c3`, 

             *         `childs`.`data` AS `t1_c4` 

             * FROM `AuthItemChild` `t`  

             * LEFT OUTER JOIN `AuthItem` `childs` 

             *         ON (`t`.`child`=`childs`.`name`)  

             * WHERE (`t`.`parent`=:yp0) 

             * ORDER BY childs.name

             */

            $result = $this->findAllByAttributes(

                array('parent'=>$tree['this']->name), // <--- that is secure but works only on main Table and not on joined Tables

                array(

                    'with' => 'childs',

                   'order' => 'childs.name',

                    )

            );

            /*

            $result = $this->findAll(

                array(

                    'with' => 'childs',

                    'condition' => "t.parent' = '{$tree['this']->name}'",//  <--- works on joined Tables but is unsecure and dont works with values like "'´`

                    'order' => 'childs.name',

                    )

            );

            */

            $depth++;

            if (count($result) > 0)

            {

                foreach($result as $row){

                    $tree['childs'][] = $this->_buildItemTree(

                        array(

                            'depth' => $depth,

                            'parent-name' => $row->parent,

                            'this-name' => $row->childs->name,

                            'this' => $row->childs, 

                            'childs' => array()

                        ), $depth

                    );

                }

            }

            return $tree;

        }

The problem is the ‘condition’ with findAll method where the condition works fine on joined tables




findAll...

'condition' => "t.parent = $userInput"

...

Bit if $userInput contains chars like ´`" or ’ this fine example crashes.

Iif I Use findAllByAttributes like this:


 $result = $this->findAllByAttributes(

                array('t.parent' => $userInput),

                array(

                'with' => array('parents', 'childs'),

                'order' => 'parents.parent DESC'

                )

            );

there are no Problems with special chars like ´`" or ’

but the condition don’t works on joined Tables

So I can use a unsecure version (findAll)that provides conditions in joined tables (I don’t want that)

or I can use a secure version (findAllByAttributes) that do NOT provide conditions in joined tables (I do not want that too)

But I want a secure version that provides condtions in joined tables and I don’t know how to do that!

Hi, I found a solution here:

http://www.yiiframework.com/doc/api/CActiveRecord#with-detail

and here

http://www.yiiframework.com/doc/guide/database.arr#disambiguating-column-names

For the first try that works:


$ct=new CDbCriteria(array('order' => 'childs.name',));

$ct->addColumnCondition(array('t.parent'=>$tree['this']->name));

$result = AuthItemChild::model()->with('childs')->findAll($ct);


// where the main trick is in the "eagerLoad" with the "with()" command

// ...AuthItemChild::model()->with('childs')->findAll...

There will be more elegant ways as this raw tryout, but thats the direction at all :)

Thanks :D