Location: PHPKode > scripts > LINQ In PHP > D3Linq.php
<?php
    /**
    * @name        D3Linq | Linq In Php
    * @version     1.6.0
    * @author      Tufan Baris YILDIRIM
    * @link        htpp://www.tufyta.com
    * @since       20.10.2009
    *
    * v1.6.0
    * =======
    * - d3grid Integrated.
    * - i've re-written some complex code blocks.
    *
    * v1.5.5
    * ======
    * - xml_string() added for xml string vars.also xml_file can select from xml string var.
    * - tags which have 2 letters (eg. li ul dt dl etc..) parsing bug [fixed]
    * - added preg_quote to LIKE creater function. [fixed]
    * - added a control for integer keys on unsetByArray [fixed]
    * v1.5.4
    * =======
    * - html tag names lowered after crawl
    * - unsetByArray added for unset variables which created by extract();
    * - all rows was returning when first row is matched and other hasn't got same columns (resolved by usetByArray) [fixed]
    * v1.5.3
    * ======
    * - GetContentsFunc public variable added  for change  file_get_contents func as u declared. Ex: curl
    * - Notice Errors resolved.
    * - much moreee stronger html parser (:
    * - dir_file and dir_files functions added for select dirs or files from a dir. ex: select from dir_files(dirname) WHERE  name LIKE '%myfile%'
    * v1.5.2
    * ======
    * - new json_file(  can read serialized data by php or json encoded data
    * - performed about stabilization . unsetted big arrays and unnecessaried used variables
    * - bug about dot obje to an array when child obje key is numeric [fixed]
    *   -- Tools Funcsions Added --
    * -  arrayRebuild
    *    ------------
    * - Can Rebuild an array by a template you given
    * - getArrayName
    *   -------------
    * - return last array name .. or last created virtual arrayname after query.
    * - getResult
    *   -------------
    * - get all result array.
    * v1.5.1
    * ======
    * - text_file(); function added.
    *                  .Ex: select line,text from text_file(file.txt) where line=50 OR text LIKE '%linq%'
    * - html_file(); function added.
    *                  .Ex: select  innertHTML,text FROM html_file(http://tufyta.com).div WHERE class='post_title';
    * - name of selected array by func cannot start with a numeric char [fixed]
    * - "NOT" support added for LIKE claueses.
    * - debug() func added. can selfdebug on error if OnError=='selfdebug';
    * - Token Analyzer and Token errors Added.
    * - CreateWhereClause Func Added for create a boolean returnable php code from WHERE clause you wroten
    * v1.5.0
    * ======
    * - FirstOf() function changed.(used foreach).
    * - Order by bug fixed (invalid column error when column has a space char).
    * - Updatable keys and values (UPDATE array SET value=....).
    * - Array Update errors added.
    * - Func Support Added. (can create and use this func in queries)
    *      . json_file().
    *          - can read json to a global array and select from it
    *      .xml_file().
    *          - can read a xml file (as dataset) to a global array and select from it or a datatable in it.
    * v1.4.0
    * ======
    * - UPDATE statement Added Thanx to Ridvan  http://www.phpclasses.org/browse/author/668797.html
    * - data_seek bug [fixed] reported by Ridvan Karatas at  http://www.phpclasses.org/discuss/package/5893/thread/1/
    * - Order by bug [fixed]
    * - Delete bug (couldnt use after order ) [fixed]
    * v1.3.0
    * ======
    * - Insert Statement Added.
    *      . Can use insert statement like '(key,value) VALUES (...,...) for 1 dimmensional arrays
    *      . and like  (col1,col2,col3) VALUES (..)  for multi dimmensional arrays'
    * v1.2.1
    * =======
    * - Columns can be used as a string in where clause [added]
    * - Last Column Name was wrong. [fixed]
    * - Order was wrong for numerics. [fixed]
    * - Distinct method had an error about implode. [fixed]
    * v1.2.0
    * ======
    * - DISTINCT Support Added.
    * v1.1.0
    * ======
    * - Created Wagons for Easy parse Tokens
    * - ORDER BY Support Added.
    * - Unknown column Error added. Checker for columns are used on ORDER Clauses
    * v1.0.2
    * ======
    * - affected_rows() func added.
    * v1.0.1
    * ======
    * - Delete Statemend added. Can Delete any object from an array ( global )
    * v1.0
    * ======
    * - This Class can be used for select from arrays as a sql query
    * - You;
    * - Can use php codes in Where clauses
    * - Can also use alias for key and value
    * - And can select array in array as  arrayname.elementname
    */
    class D3Linq{

        public    $OnError = 'selfdebug',
        $GetContentsFunc,
        $DebugDeepLimit =0,
        $DebugDeep      =0;

        private   $Index          =0,
        $IndexIn        =0,
        $Result         =array(),
        $Selected       =array(),
        $Dizimiz        =array(),
        #$ResultKeys    =array(),
        #$ResultValues  =array(),
        $isBasic        =False,
        $isComplicated  =False,
        $Tokens         =array(),
        $ErrorMsg       ='',
        $ErrorCode      ='',
        $AffecTedRows   =0,
        $LastSQL        ='',
        /**
        * Token Train
        * @since v1.1.0
        * @var mixed
        */
         $wagons=array(
                'statement'         =>array('wagon' => 'SELECT|DELETE|INSERT|UPDATE','options'=>'','msg'=>'Statement can only be Select,Delete,Insert or Update'),
                'space_1'           =>array('wagon' => '[\s]+','options'=>'?'),
                'unique'            =>array('wagon' => 'DISTINCT','options'=>'?'),
                'columns'           =>array('wagon' => '[a-zA-Z0-9\s,]+|\*|[^\(\s]+','options'=>'?'),
                'space_2'           =>array('wagon' => '[\s]+','options'=>'?'),
                'fromorinto'        =>array('wagon' => 'FROM|INTO','options'=>'','msg'=>'You must use this token either FROM or INTO'),
                'space_3'           =>array('wagon' => '[\s]+','options'=>''),
                'func_name'         =>array('wagon' => 'json_file|xml_file|text_file|html_file|dir_files?|xml_string','options'=>'?'),
                'func_pr1'          =>array('wagon' => '\(','options'=>'?'),
                'arrayname'         =>array('wagon' => '[A-Za-z_0-9\.\[\]\\\:\/%_&\?=\-]+','options'=>'','msg'=>'UnReachable Array'),
                'func_pr2'          =>array('wagon' => '\)','options'=>'?'),
                'func_in'           =>array('wagon' => '\.[A-Za-z_0-9\.\@]+','options'=>'?'),
                'space_4'           =>array('wagon' => '[\s]+','options'=>'*'),

                //Update Clause @since v1.4.0
                'updateClause'      =>array('wagon' => array(
                                                            'set'       =>array('wagon'=>'SET','options'=>''),
                                                            'set_space' =>array('wagon'=>'[\s]+','options'=>''),
                                                            'colandval' =>array('wagon'=>'[A-Za-z0-9_-]+\=.*','options'=>'+'),
                                                            ),
                                                            'options'=>'?'
                                                            ),

                // INSERT Clause  @since v1.3.0
                'insertClause'       =>array('wagon' => array(
                                                        'insertColumns' =>array('wagon'=>'\([a-zA-Z0-9\s,]+\)','options'=>'?'),
                                                        'space_bval'    =>array('wagon'=>'[\s]+','options'=>'?'),
                                                        'values'        =>array('wagon'=>'VALUES','options'=>'?'),
                                                        'space_val'     =>array('wagon'=>'[\s]+','options'=>'?'),
                                                        'colvals'       =>array('wagon'=>'\([^\(]+\)','options'=>'?'),
                                                        ),'options'=>'?'
                                                        ),

                // Where Clause
                'whereClause'       =>array('wagon' => array(
                                                        'where'         =>array('wagon'=>'WHERE','options'=>''),
                                                        'space_where'   =>array('wagon'=>'[\s]+','options'=>''),
                                                        'whereCondition'=>array('wagon'=>'[^;]+','options'=>''),
                                                        ),'options'=>'?'
                                                        ),
                // Order Clause
                'orderClause'       =>array('wagon'=>array(
                                                        'order'             =>array('wagon'=>'ORDER','options'=>''),
                                                        'space_order'       =>array('wagon'=>'[\s]+','options'=>'*'),
                                                        'by'                =>array('wagon'=>'BY','options'=>''),
                                                        'orderCondition'    =>array('wagon'=>'[^;]+','options'=>''),
                                                        ),'options'=>'?'
                                                        )
                ),
                $train;
        #Tokens Index
        const    QR_INDEX                =0,                 // Query Index              #0

        # @since v1.2.0
        UNQ_INDEX               ='unique',
        ST_INDEX                ='statement',       // Statement type Index     #1
        AR_INDEX                ='arrayname',       // Array name Index         #7
        CL_INDEX                ='columns',         // Column Index             #3
        AL_COUNT                =8,                 // Count of matches for a basic query (without WHERE clause)        #8   passive on v1.1.0
        WH_COUNT                =13,                // Count Of matches for a complicated query (with WHERE clauses)    #13  passive on v1.1.0
        CM_WHINDEX              ='whereCondition',  // Where Clause index when is complicated                           #12
        # @since v1.1.0
        OR_INDEX                ='orderCondition',  // Order Clause index       #15
        # @since v1.3.0
        IN_COLS                 ='insertColumns',
        IN_COLVALS              ='colvals',
        # @since v1.4.0
        UP_COLVALS              ='colandval';

        # Errors with Codes
        const    INVALID_SQL             ='010|Invalid SQL',
        MISSING_OPERATORS       ='020|Missing operators',
        MISSING_P               ='021|Missing %1 parenthesis',
        UNEXCEPTED_ERROR        ='030|Unexcepted "<b><i>%1</i></b>"',
        EXCEPTED_BUT            ='031|Excepted "<b><i>%1</i></b>"  but found "<i>%2</i>"',
        NOT_AN_ARRAY            ='040|%1 is not an array',
        NOT_AN_INTEGER          ='041|%1 is not an integer value on %2',
        # @since v1.1.0
        UNKNOWN_COLUMN          ='051|Unknown column "<b>%1</b>"',
        # @since v1.5.0
        UNSUPPORTED_STATEMENT   ='060|Un Supported statement "<b>%1</b>"',
        UNSUPPORTED_FUNCTION    ='061|Un Supported function "<b>%1</b>"',
        ALREADY_HAS_KEY         ='070|The array "<b>%1</b>" already has "<b>%2</b>"',
        FILE_NOT_EXISTS         ='080|"<b>%1</b>" File not exists',
        # @sine v1.5.3
        NOT_A_DIR               ='090|<b>%1</b> is not a directory';




        /**
        * Constructor
        */
        public function __construct()
        {
            $this->Index                =0;
            $this->IndexIn              =0;
            $this->ErrorMsg             ='';
            $this->ErrorCode            ='';
            #$this->ResultKeys          =array();
            #$this->ResultValues        =array();
            $this->Result               =array();
            $this->Selected             =array();
            $this->isBasic              =False;
            $this->isComplicated        =False;
            $this->Tokens               =array();
            $this->AffecTedRows         =0;
            // $this->train=$this->train ? $this->train : $this->CreateTrain(); # passived in v1.3.1
        }


        /**
        * Main Qery Parser
        * @param mixed $SQL it must be valid and basic sql query string
        */
        public function Query($SQL)
        {
            $this->__construct(); // Reset object. its soo useful on singletion using (:
            $this->LastSQL = $SQL = $this->Escape($SQL);

            #@since v1.1.0
            if(preg_match('/'.$this->CreateTrain($this->wagons['orderClause']['wagon']).'/is',$SQL))
                $this->wagons['orderClause']['options'] = '';
            else
                $this->wagons['orderClause']['options'] = '?'; # @since v1.3.1


            #@since v1.4.0
            if( strtoupper($this->FirstOf(explode(' ',$SQL))) == 'UPDATE' )
            {
                $this->wagons['from']['options'] = '{0}';
                $this->wagons['columns']['options'] = '{0}';
            }
            else {
                $this->wagons['from']['options'] = '';
                $this->wagons['columns']['options'] = '?';
            }

            if(preg_match('/'.$this->CreateTrain($this->wagons['whereClause']['wagon']).'/is',$SQL))
            {
                $this->wagons['whereClause']['options'] = '';

            }
            else
            {

                $this->wagons['whereClause']['options'] = '?'; # @since v1.4.0
            }

            $this->train = $this->CreateTrain();
            preg_match('/'.$this->train.'/is',$SQL,$this->Tokens);

            if(count($this->Tokens) == 0)
                $this->Error(self::INVALID_SQL);

            $this->isComplicated = !empty($this->Tokens[self::CM_WHINDEX]);

            $RpCount = self::CountIn('\)',$this->Tokens[self::QR_INDEX]);
            $LpCount = self::CountIn('\(',$this->Tokens[self::QR_INDEX]);

            if($RpCount!= $LpCount)
            {
                if($RpCount<$LpCount)
                {
                    $this->Error(self::MISSING_P,'right');
                }
                else
                {
                    $this->Error(self::MISSING_P,'left');
                }
            }
            Unset($RpCount,$LpCount);
            #@since v1.5.0
            if ( $this->Tokens['func_name'] )
            {
                $call = $this->Tokens['func_name'];

                if (method_exists($this,$call))
                {
                    $this->$call($this->Tokens['arrayname']);
                }
                else
                {
                    $this->Error(self::UNSUPPORTED_FUNCTION,$call);
                }
            }

            switch (strtoupper($this->Tokens[self::ST_INDEX])){
                case 'SELECT':
                    $this->Select($this->Tokens);
                    break;
                case 'DELETE':
                    $this->Delete($this->Tokens);
                    break;
                case 'INSERT':
                    $this->Insert($this->Tokens);
                    break;
                case 'UPDATE':
                    $this->Update($this->Tokens);
                    break;
                default:
                    $this->Error(self::UNSUPPORTED_STATEMENT,$this->FirstOf(explode(' ',$SQL)));
                    break;
            }

        }
        /**
        * Set the index of current Row
        * @param mixed $Int
        */
        public function data_seek($Int)
        {
            if( is_numeric($Int) )
                $this->Index = $Int;
            else
                $this->Error(self::NOT_AN_INTEGER,array($Int,__FUNCTION__));
        }
        /**
        * Get Unfetched Count
        * @return int
        */
        public  function num_rows()
        {
            return count($this->Result)-$this->Index;
        }


        /**
        * Get Selected Or Deleted Record Counts
        * @since 1.0.2
        */
        public function affected_rows()
        {
            return $this->AffecTedRows;
        }
        /**
        * Fetch Result As D3Field. Return false if no result.
        * @return D3Object or False
        */
        public function fetch_object()
        {
            return   ($Object = $this->fetch_assoc())
            ? (object)$Object
            : false;
        }
        /**
        * Convert the obje name as  arrayname.indname ..to array arrayname[indname]
        * @param mixed $dottedObject
        */
        private function dotObjectToArray($dottedObject)
        {
            if(preg_match('/([A-Z0-9_\.]+)/i',$dottedObject))
            {
                $objs = explode('.',$dottedObject);
                $arrName = $objs[0];
                global $$arrName;
                $globalEleman = $$arrName;

                foreach($objs as  $index=>$name)
                {
                    if($index>0)
                    {
                        $globalEleman = isset($globalEleman[$name])?$globalEleman[$name]:null;
                        $globalName.= '['.$name.']';
                    }
                    else
                        $globalName = $name;
                }

                if(!is_array($globalEleman))
                    $this->Error(self::NOT_AN_ARRAY,$dottedObject);
                else
                    return array('array'=>(array)$globalEleman,'global'=>$globalName,'arrName'=>$arrName);

            }
            else
            {
                $this->Error(self::NOT_AN_ARRAY,$dottedObject);
            }
            return $dottedObject;

        }
        /**
        * My Train Creater Recursive Function by using wagons (:  Cuff Cuuuuffff.... (:
        */
        private function CreateTrain()
        {
            $GetWagons = func_num_args()>0 ? func_get_arg(0) : $this->wagons;
            $Wagon = '';
            foreach($GetWagons AS $wagonName=>$wagonBulk)
            {
                $Wagon .= '(';
                $Wagon .= (isset($wagonBulk['wagon']) && is_array($wagonBulk['wagon'])) ? $this->CreateTrain($wagonBulk['wagon']) : (is_numeric($wagonName) ? null: '?<'.$wagonName.'>').(isset($wagonBulk['wagon']) ? $wagonBulk['wagon'] : null);
                $Wagon .= ')'.$wagonBulk['options'];
            }
            return $Wagon;

        }


        /**
        * public Fetch Result as an Array. return false if not have result
        * @return Array or False
        */
        public function fetch_assoc()
        {
            return isset($this->Result[$this->Index]) ? $this->Result[$this->Index++] :false;
        }
        /**
        * private Fetch Result as an Array. return false if not have result
        * @return Array or False
        */
        private function fetch()
        {
            if(isset($this->Selected[$this->IndexIn]))
            {
                if($this->Tokens[self::CL_INDEX] == '*')
                {
                    $Assoc = $this->Selected[$this->IndexIn];
                    if(is_array($this->Dizimiz))
                        Unset($Assoc['key'],$Assoc['value']);
                }
                else
                {
                    preg_match_all('/(key|value'.(is_array($this->Dizimiz)?'|'.implode('|',array_keys($this->Dizimiz)):null).')((([\s]+)as)?([\s]+)([^,]+))?/i',$this->Tokens[self::CL_INDEX],$ColumnsWithAlias);
                    foreach($ColumnsWithAlias[1] as $colndx=>$colname)
                    {
                        $Assoc[trim(trim($ColumnsWithAlias[6][$colndx]) ? $ColumnsWithAlias[6][$colndx] : $colname)] = $this->Selected[$this->IndexIn][$colname];
                    }

                }
                unset($this->Selected[$this->IndexIn]);
                $this->IndexIn++;
                return $Assoc;

            }
            else
            {
                return False;
            }
        }
        /**
        * Main Selector Function
        * @param mixed $Matches Tokens.
        */
        private function Select($Matches)
        {
            $getObj = $this->dotObjectToArray($Matches[self::AR_INDEX]);
            $Dizimiz = $getObj['array'];

            is_array($Dizimiz) || $this->Error(self::NOT_AN_ARRAY,$Matches[self::AR_INDEX]);

            $this->Dizimiz = $Dizimiz[$this->firstKey($Dizimiz)];
            $sart= $this->isComplicated ? $this->createWhereClause($Matches,$Dizimiz): true;

            foreach ($Dizimiz as $key=>$value)
            {
                if (is_array($value))
                    extract($value,EXTR_OVERWRITE);

                $SartSaglandi = false;
                @eval('$SartSaglandi = (boolean)('.$sart.');');
                if(!$this->isComplicated || $SartSaglandi)
                {
                    /* $this->ResultValues[] = $value;
                    $this->ResultKeys[] = $key; */
                    if((isset($Dizi) && is_array($Dizi)) || is_array($Dizi = $this->Dizimiz))
                        $Selected = $value;
                    $Selected['key'] = $key;
                    $Selected['value'] = $value;
                    $this->Selected[] = $Selected;
                    $this->AffecTedRows++;
                }
                unset($Dizimiz[$key]);
                if (is_array($value))
                    eval($this->unsetByArray(array_keys($value)));
            }
            # @since v1.1.0  MultiCols
            while($Fetched = $this->fetch())
                $this->Result[] = $Fetched;


            # @since v1.1.0  ORDER BY
            if($this->Tokens[self::OR_INDEX])
                $this->Result = $this->OrderArray($this->Result,$this->Tokens[self::OR_INDEX]);


            # @since v1.2.0   DISTINCT
            if($this->Tokens[self::UNQ_INDEX])

                $this->Result = $this->Uniquarray($this->Result);


            return $this;
        }
        /**
        * Return First key of given array.
        *
        * @param mixed $Array
        * @return mixed
        */
        private function firstKey($Array)
        {
            if(is_array($Array))
            {
                foreach ($Array as $FirstKey=>$FirstValue)
                {
                    return $FirstKey;
                }
            }
            else return 0;
        }

        /**
        * Sorter Function
        * @since v1.1.0
        *
        * @param array $array
        * @param string $cols
        */
        private function OrderArray($ArrayBeSorted,$OrderString)
        {
            $orCondCol = explode(',',$OrderString);
            foreach ($orCondCol as $ColAndOrder)
            {
                preg_match('/(.*)([\s]+)(ASC|DESC)/is',$ColAndOrder,$OrdCol);
                if(!array_key_exists(trim($OrdCol[1]),$this->Result[0]))
                {
                    $this->Error(self::UNKNOWN_COLUMN,trim($OrdCol[1]));
                }
                else
                {

                    $Columns[trim($OrdCol[1])] = 'SORT_'.strtoupper(trim($OrdCol[3]));

                }
            }
            $colarr = array();
            foreach ($Columns as $col => $order)
            {
                $colarr[$col] = array();
                foreach ($ArrayBeSorted as $k => $row) { $colarr[$col]['_'.$k] = strtolower($row[$col]); }
            }
            $runIt = 'array_multisort(';
            foreach ($Columns as $col => $order)
            {
                $runIt .= '$colarr[\''.$col.'\'],'.$order.',';
            }
            $runIt = substr($runIt,0,-1).');';
            eval($runIt);
            $SortedArray = array();
            foreach ($colarr as $col => $arr)
            {
                foreach ($arr as $k => $v)
                {
                    $k = substr($k,1);
                    if (!isset($SortedArray[$k])) $SortedArray[$k] = $ArrayBeSorted[$k];
                    $SortedArray[$k][$col] = $ArrayBeSorted[$k][$col];
                }
            }

            foreach ($SortedArray as $SortElem)
            {
                $ReSortedArray[] = $SortElem;
            }

            return $ReSortedArray;
        }

        /**
        * Unique Function for DISTINCT
        * @since v1.2.0
        */
        private function Uniquarray($Array)
        {
            $newArray = '';
            foreach ($Array as $Arraykey=>$ArrayValue)
            {
                $newArray[implode(',',$ArrayValue)] = $ArrayValue;
            }
            return is_array($newArray) ? array_values($newArray) : array();
        }

        /**
        * Main Deleter Function
        * @since v1.0.2
        * @param mixed $Matches Tokens.
        */
        private function Delete($Matches)
        {
            $getObj = $this->dotObjectToArray($Matches[self::AR_INDEX]);
            $Dizimiz = $getObj['array'];
            if(!is_array($Dizimiz))
            {
                $this->Error(self::NOT_AN_ARRAY,$Matches[self::AR_INDEX]);
            }
            if($this->isComplicated)
            {
                $sart = $this->createWhereClause($Matches,$Dizimiz);
            }
            else
            {
                $sart = true;
            }

            foreach ($Dizimiz as $key=>$value)
            {
                if (is_array($value)) extract($value,EXTR_OVERWRITE);
                @eval('$SartSaglandi = ('.$sart.');');
                if(!$this->isComplicated || $SartSaglandi)
                {
                    $deleteCode = 'global $'.$getObj['arrName'].'; unset($'.$getObj['global'].'['.$key.']);';

                    eval($deleteCode);
                    $this->AffecTedRows++;
                }
            }
            return $this;
        }

        /**
        * Insert Statement
        * Can input elements for all array.
        *
        * @since v1.3.0
        * @param mixed $Matches
        */
        private function Insert($Matches)
        {
            $Matches = $Matches ? $Matches : $this->Tokens;
            $gArray = $this->dotObjectToArray($this->Tokens[self::AR_INDEX]);
            $inCols = str_replace(array(')','('),'',$Matches[self::IN_COLS]);
            $colNames = explode(',',$inCols);
            $colVals = str_replace(array('(',')',')','\'','\,'),'',$Matches[self::IN_COLVALS]);
            $colValues = explode(',',$colVals);
            foreach ($colNames as $ind=>$Name)
            {
                $evuLateIt ='global $'.$gArray['arrName'].';$'.$gArray['global'].'['.(($Name == 'key' || $Name == 'value') ? $this->Escape($colValues[$this->FindIndByVal($colNames,'key')],true) :NULL).'] = '.(($Name == 'key' || $Name == 'value') ? '\''.$this->Escape($colValues[$this->FindIndByVal($colNames,'value')],true).'\';' :'array('.$this->ArrayToString($colNames,$colValues).');');
                @eval($evuLateIt);
                $this->AffecTedRows++;
                break;
            }
            return $this;
        }
        /**
        * Update Function
        * @since v1.4.0
        * @param mixed $Matches
        */
        private function Update($Matches)
        {
            $getObj = $this->dotObjectToArray($Matches[self::AR_INDEX]);
            $Dizimiz = $getObj['array'];
            if(!is_array($Dizimiz))
            {
                $this->Error(self::NOT_AN_ARRAY,$Matches[self::AR_INDEX]);
            }
            if($this->isComplicated)
            {
                $sart = $this->createWhereClause($Matches,$Dizimiz);
            }
            else
            {
                $sart = true;
            }

            foreach ($Dizimiz as $key=>$value)
            {
                if (is_array($value)) extract($value,EXTR_OVERWRITE);
                @eval('$SartSaglandi = ('.$sart.');');
                if(!$this->isComplicated || $SartSaglandi)
                {

                    $allCols = explode(',',$this->Escape($Matches[self::UP_COLVALS]));
                    foreach ($allCols as $collString)
                    {
                        preg_match('/(.*)=\'(.*)\'/is',$collString,$mTs);

                        switch($mTs[1])
                        {
                            case 'key':
                                if(array_key_exists($mTs[2],$getObj['array']))
                                {
                                    $this->Error(self::ALREADY_HAS_KEY,array($getObj['arrName'],$mTs[2]));
                                }
                                else
                                {
                                    $updateCode = 'global $'.$getObj['arrName'].'; $'.$getObj['global'].'['.$mTs[2].'] = $'.$getObj['global'].'['.$key.']; unset($'.$getObj['global'].'['.$key.']);';
                                }
                                break;
                            case 'value':
                                $updateCode = 'global $'.$getObj['arrName'].'; $'.$getObj['global'].'['.$key.']=\''.$mTs[2].'\';';
                                break;
                            default:
                                $updateCode = 'global $'.$getObj['arrName'].'; $'.$getObj['global'].'['.$key.']['.$mTs[1].']=\''.$mTs[2].'\';';
                                break;
                        }
                        eval($updateCode);
                    }
                    $this->AffecTedRows++;
                }
            }
            return $this;
        }
        /**
        * XML File To Array
        * @since v1.5.0
        * @param $fileName file Url
        */
        private function xml_file($fileName)
        {
            $varName = 'x'.md5($fileName);
            global $$varName,$$fileName;
            $$varName = $this->ObjectToArray((array)simplexml_load_string(isset($$fileName) ? $$fileName : $this->getContent($fileName)));
            $this->Tokens[self::AR_INDEX] = $varName.$this->Tokens['func_in'];
        }
        /**
        * XML string to array
        * @since v1.5.5
        * @param mixed $variableName variable name as string
        */
        private function xml_string($variableName)
        {
            $this->xml_file($variableName);
        }
        /**
        * Object To array Recursive
        * @since v1.5.0
        * @param mixed $data
        * @return mixed
        */
        private function ObjectToArray($data)
        {
            $nData = array();
            foreach ((array)$data as $k=>$v)
            {
                $nData[$k] = (is_object($v) || is_array($v)) ? self::ObjectToArray($v): $v;
            }
            return $nData;
        }
        /**
        * Convert Where Clause to a PHP Code can return Boolean
        * @since v1.5.1
        * @param mixed $Matches
        * @param mixed $Dizimiz
        * @return mixed
        */
        private function createWhereClause($Matches,$Dizimiz)
        {
            $sart = $Matches[self::CM_WHINDEX];
            $sart = preg_replace('/(key|value'.(is_array($Dizimiz[$this->firstKey($Dizimiz)])?'|'.implode('|',array_keys($Dizimiz[$this->firstKey($Dizimiz)])):null).')(=|==|<|>|<=|>=)/i','$$1$2',$sart);
            $Find = array('key=','value=','\'.key.\'','\'.value.\'');
            $Replace = array('key==','value==','$key','$value');
            $sart = str_replace($Find,$Replace,$sart);
            if (is_array($Dizimiz[$this->firstKey($Dizimiz)]))
            {
                foreach ($Dizimiz[$this->firstKey($Dizimiz)] AS $keyName=>$keyVal)
                {
                    $Find = array($keyName.'=','\'.'.$keyName.'.\'');
                    $Replace = array($keyName.'==','$'.$keyName);
                    $sart = str_replace($Find,$Replace,$sart);
                }
            }

            # preg_match_all('/(key|value'.(is_array($Dizimiz[$this->firstKey($Dizimiz)])?'|'.implode('|',array_keys($Dizimiz[$this->firstKey($Dizimiz)])):null).')([\s]+)(not\s+)?(LIKE)*([\s]+)(\')*([^\'\n]+)(\')*/i',$sart,$likeMatches);

            /*
            foreach ($likeMatches[0] AS $ind=>$cm){
            $sart = (trim($likeMatches[3][$ind])?'!' :null).'preg_match(\'/^'.str_replace('%','(.*)',$likeMatches[7][$ind]).'$/i\',$'.$likeMatches[1][$ind].')';
            }
            */
            $pattern = '/(key|value'.(is_array($Dizimiz[$this->firstKey($Dizimiz)])?'|'.implode('|',array_keys($Dizimiz[$this->firstKey($Dizimiz)])):null).')([\s]+)(not\s+)?(LIKE)*([\s]+)(\')*([^\'\n]+)(\')*/i';
            $sart = preg_replace($pattern,'(trim(\'$3\')?\'!\' :null).preg_match(\'/^\'.str_replace(\'%\',\'(.*)\',preg_quote(\'$7\')).\'$/i\',$$1)',$sart);
            return $sart;

        }
        /**
        * HTML Tags To an Array
        * @since v1.5.1
        * @param mixed $fileName
        */
        private function html_file($fileName)
        {
            $varName = 'h'.md5($fileName);
            global $$varName;
            $Tags = Array();
            $Attributes = Array();
            $Values = Array();
            $DataBase = Array();

            $this->MatchTags($this->getContent($fileName),$Tags,$Attributes,$Values);

            foreach ($Tags as $Tind=>$TagName)
            {
                $DataBase[$TagName][$Tind] = array("tag_id"=>$Tind,'innerHTML'=>$Values[$Tind],'text'=>strip_tags($Values[$Tind]));
                if(preg_match_all('/([A-Z0-9]+)=((\'|")?([^\'"]+)(\'|")?)/is',$Attributes[$Tind],$MatchedAttr))
                {
                    if(count($MatchedAttr[0])>0)
                    {
                        for ($i = 0; $i < count($MatchedAttr[0]); $i++)
                        {
                            $DataBase[$TagName][$Tind][$MatchedAttr[1][$i]] = $MatchedAttr[4][$i];
                        }
                    }
                }
                unset($Tags[$Tind],$Attributes[$Tind],$Values[$Tind]);
            }
            $$varName = $DataBase;
            unset($DataBase);
            $this->Tokens[self::AR_INDEX] = $varName.$this->Tokens['func_in'];
        } function MatchTags($htmlCode, &$Tags, &$Attributes, &$Values)
        {
            preg_match_all('/<([a-z0-9\-]+)([^>]+)?>(([^\<]+)?<\/\1>)?/i', $htmlCode, $Matches);
            if (count($Matches[0]) != 0)
            {
                for ($i = 0; $i < count($Matches[0]); $i++)
                {
                    $Tags[] = strtolower(trim($Matches[1][$i]));
                    $Attributes[] = trim($Matches[2][$i]);
                    $Values[] = trim($Matches[4][$i]);
                    if (trim($Matches[4][$i]) != '' and preg_match('/<[a-z0-9\-]+.*?>/is', $Matches[4][$i]))
                    {
                        $this->MatchTags($Matches[4][$i], $Tags, $Attributes, $Values);
                    }

                }
            }

        }
        /**
        * Read file(s)? or director(i|y)(es)? names from a diretory   | regexp :D
        * @since v1.5.3
        */
        private function dir_file($dirName)
        {
            $this->dir_files($dirName);
        }
        private function dir_files($dirName)
        {
            $varName = 'd'.md5($dirName);
            global $$varName;
            if (!is_dir($dirName)){
                $this->Error(self::NOT_A_DIR,$dirName);
                return array();
            }
            $filesFolders = array();
            $dirHandle = opendir($dirName);
            $fileID = 0;
            while ($Chield = readdir($dirHandle))
            {
                $cat = is_dir($dirName.'/'.$Chield)? 'dirs' : 'files';
                $filesFolders[$cat][$fileID]['name']    =$Chield;                           # File or folder name
                $filesFolders[$cat][$fileID]['ctime']   =filectime($dirName.'/'.$Chield);   # Creation Time
                $filesFolders[$cat][$fileID]['atime']   =fileatime($dirName.'/'.$Chield);   # Last Access Time
                $filesFolders[$cat][$fileID]['mtime']   =filemtime($dirName.'/'.$Chield);   # Last Modification Time
                $filesFolders[$cat][$fileID]['size']    =filesize($dirName.'/'.$Chield);    # File Size as Byte
                $filesFolders[$cat][$fileID]['type']    =filetype($dirName.'/'.$Chield);    # File or Folder
                $filesFolders[$cat][$fileID]['ext']     =end(explode('.',$Chield));         # File Extension
                $fileID++;
            }
            closedir($dirHandle);

            if ($this->Tokens['func_in']!= '.dirs' && $this->Tokens['func_in']!= '.files')
                $$varName = array_merge($filesFolders['dirs'],$filesFolders['files']);
            else
                $$varName = $filesFolders;

            $this->Tokens[self::AR_INDEX] = $varName.$this->Tokens['func_in'];
        }

        /**
        * Json File to an Array
        * @since v1.5.0
        * @param mixed $fileName
        */
        private function json_file($fileName)
        {
            $varName = 'j'.md5($fileName);
            global $$varName;
            $$varName = $this->ObjectToArray(($jsDecode = json_decode($Content = $this->getContent($fileName)))? $jsDecode : unserialize($Content));
            $this->Tokens[self::AR_INDEX] = $varName.$this->Tokens['func_in'];
        }
        /**
        * File Lines To Array
        * @since v1.5.0
        * @param mixed $fileName
        */
        private function text_file($fileName)
        {
            $varName = 't'.md5($fileName);
            global $$varName;

            $lines = $this->getContent($fileName,true);
            $newArray = Array();
            foreach ($lines AS $lineNum=>$Text){
                $newArray[] = array('line'=>$lineNum,'text'=>$Text);
            }

            $$varName = $newArray;
            unset($newArray);
            $this->Tokens[self::AR_INDEX] = $varName.$this->Tokens['func_in'];
        }
        /**
        * get Contents From an url or a file
        *
        * @param mixed $url
        * @return string
        */
        private function getContent($url,$File = False)
        {
            return function_exists($this->GetContentsFunc) ? call_user_func($this->GetContentsFunc,$url) : ($File ? @file($url) : @file_get_contents($url));
        }

        /**
        * Return a String as an array build for eval();
        * @since v1.3.0
        *
        * @param mixed $KeyArr
        * @param mixed $ValArr
        * @return string
        */
        private function  ArrayToString($KeyArr,$ValArr)
        {
            $elems = array();
            foreach ($KeyArr AS $ind=>$Val)
            {
                $elems[] = '"'.$Val.'"=>"'.$this->Escape($ValArr[$ind],true).'"';
            }
            return implode(',',$elems);
        }

        /**
        * Deactive Escape Characters
        * @since v1.3.0
        *
        * @param mixed $String
        * @param mixed $UnEscape
        */
        private function Escape($String,$UnEscape = False)
        {
            $Unex = array('\(','\\\'','\)','\,');
            $Ex = array('D3Linq::ExedRPhar','D3Linq::ExedQuot','D3Linq::ExedRPhar','D3Linq::ExedVir');
            return $UnEscape ? str_replace($Ex,$Unex,$String) : str_replace($Unex,$Ex,$String);
        }

        /**
        * Find First Value index what you given.
        *
        * @since v1.3.0
        *
        * @param mixed $Array
        * @param mixed $Val
        * @return mixed
        */
        function FindIndByVal($Array,$Val)
        {
            return array_search($Val,$Array);
        }

        /**
        * Error Creating Function
        *
        * @param mixed $String Error Template
        * @param mixed $Vals  Replace Values
        */
        private function Error($String,$Vals = False)
        {
            $ErrAndCode =explode('|',$String);
            $Error      =strip_tags($ErrAndCode[1]);
            $ErrCode    =$ErrAndCode[0];

            if(is_array($Vals))
            {
                foreach($Vals AS $key=>$value)
                {
                    $Error = str_replace('%'.($key+1),$value,$Error);
                }
            }
            elseif($Vals)
            {
                $Error = str_replace('%1',$Vals,$Error);
            }
            $this->ErrorP($Error,$ErrCode);

        }
        /**
        * Error Printing Function.
        *
        * @param mixed $String  Error Message
        * @param mixed $Code    Error Code
        */
        private function ErrorP($String,$Code = 000)
        {
            $this->ErrorMsg  =$String;
            $this->ErrorCode =$Code;
            if($this->OnError)
            {
                if($this->OnError == 'selfdebug')
                {
                    $this->debug();
                }
                else
                {
                    $this->RunEvent($this->OnError);
                }
            }else{
                die('<div><b>#'.$Code.'</b> '.$String."</div>\n");
            }
        }
        /**
        * Return First of Given Array
        *
        * @param mixed $Array
        * @return mixed  First of Array Element
        */
        private function FirstOf($Array)
        {
            foreach ($Array as $Val)
                return $Val;


        }
        /**
        * Find Char Count in a string
        *
        * @param mixed $Needle
        * @param mixed $Haystack
        * @return int  Char Count
        */
        private function CountIn($Needle,$Haystack)
        {
            preg_match_all('/([^\\\]['.$Needle.'])/i',$Haystack,$Found);
            return count($Found[1]);
        }
        /**
        * Event Runner
        *
        * @param mixed $EventName Func Name
        * @param mixed $Param  Func Param(s)
        * @return mixed Func Result which called
        */
        private function RunEvent($EventName,$Param = False)
        {
            if(function_exists($EventName)){
                if($Param){

                    if(is_array($Param)){
                        return call_user_func_array($EventName,$Param);

                    } else {
                        return call_user_func($EventName,$Param);
                    }

                }else {
                    return call_user_func($EventName);
                }
            }
        }
        /**
        * Method Caller
        * @since 1.5.0
        * @param mixed $MethodName Method Name
        * @param mixed $Param  Method Param(s)
        * @return mixed Method Result which called
        */
        private function Call($MethodName,$Param = False)
        {
            if(method_exists($this,$MethodName)){
                if($Param){
                    if(is_array($Param)){
                        return call_user_method_array($EventName,$this,$Param);

                    } else {
                        return call_user_method($EventName,$this,$Param);
                    }

                }else {
                    return call_user_method($EventName,$this);
                }
            }else {

                $this->Error(self::UNSUPPORTED_FUNCTION,$MethodName);
            }
        }
        /**
        * Get Last D3Linq Error Message
        * @return String
        */
        public function ErrorMsg()
        {
            return $this->ErrorMsg;
        }
        /**
        * GEt Last D3Linq Error Code
        * @return String
        */
        public function ErrorCode()
        {
            return $this->ErrorCode;
        }

        /**
        * Debugger Funciton
        * @since v1.5.1
        * Print Debug Information about query you wroten
        * See
        *     - Errors
        *     - Invalid Token
        *     - Valid Tokens
        */
        public function debug()
        {
            if($this->DebugDeep>$this->DebugDeepLimit) return false;
            global $Tokens;
            $Tokens = $this->Tokens;
            $db = new D3Linq();
            $db->DebugDeep = $this->DebugDeep = $this->DebugDeep+1;
            $db->OnError = false;  // no repeat no lag (:
            $db->Query("SELECT *FROM Tokens WHERE !is_numeric('.key.') AND trim('.value.')!=''");
            $KnownTokens = $db->num_rows();
            echo "
            <style type=\"text/css\">\n
            .d3linq_debug{\n
            font-size:11px;\n
            font-family:Tahoma;\n
            border:#aaa 1px solid;\n
            }\n
            .thead,.thead td{\n
            background:#ddd;\n
            color:#000;\n
            padding:3px;\
            border:1px solid;\n
            font-size:12px;\n
            font-weight:700; \n
            }\n
            .row1,.row1 td{\n
            background:#eee;\n
            padding:3px;\n
            font-size:11px;\n
            }\n
            .row0,.row0 td{\n
            background:#efefef;\n
            padding:3px;\n
            font-size:11px;\n
            }\n
            .hata,.hata td{\n
            background:#f8ced8;\n
            color:#b1136c;\n
            font-size:11px;\n
            border:1px solid;\n
            padding:3px;\n
            }\n
            </style>\n";
            $arrName = $this->FirstOf(explode('.',$this->Tokens[self::AR_INDEX]));
            $SelectedArray = (isset($$arrName) && is_array($$arrName)) ?  $this->dotObjectToArray($this->Tokens[self::AR_INDEX]):array('global'=>'Unknown');
            echo '<table width="100%" class="d3linq_debug">'."\n"
            .'<tr class="thead"><td colspan="2" align="center">D3Linq Debug</td></tr>'."\n";
            if($this->ErrorCode){
                echo '<tr class="hata"><td><b>Error</b></td><td>'.$this->ErrorMsg().' Code : '.$this->ErrorCode().'</td><tr>';
            }
            echo '<tr class="row1"><td>SQL Text</td><td>'.$this->LastSQL.'</td></tr>'."\n";
            echo '<tr class="row2"><td>Valid Tokens Count</td><td>'.$KnownTokens.'</td></tr>'."\n";
            echo '<tr class="row2"><td>Array</td><td>$'.$SelectedArray['global'].'</td></tr>'."\n";
            echo '<tr class="row1"><td>Affected Rows/Array Count</td><td>'.$this->affected_rows().'/'.count(isset($SelectedArray['array'])?$SelectedArray['array']:array()).'</td></tr>'."\n";
            echo '<tr class="row1"><td valign="top">Tokens</td><td>';
            echo '<table width="100%" class="d3linq_debug">'."\n";
            echo '<tr class="row1"><td><b>Token Name</b></td><td><b>Value</b></td></tr>'."\n";
            $r = 1;
            while ($t = $db->fetch_object())
            {
                echo '<tr class="row'.($r%2).'"><td>'.strtoupper($t->key).'</td><td>'.$this->Tokens[$t->key].'</td></tr>'."\n";
                $r++;
            }
            if($this->ErrorCode)
            {
                $sql = $this->LastSQL;
                reset($this->wagons);
                while ($token = each($this->wagons)){
                    $nToken[] = $token[1];
                    if (!preg_match('/'.$this->CreateTrain($nToken).'/i',$sql,$matched)){
                        echo '<tr class="hata"><td>Error on<br><b>'.strtoupper($token['key']).'</b></td><td><br>'.$token[1]['msg'].'<br></td></tr>';
                        break;
                    }
                    unset($nToken,$Tokens);
                }
            }
            echo '</table></td></tr>'."\n";
            echo '</table>';
        }

        /**
        * ==================================
        *  D3Linq TOOLS
        * ==================================
        * @since v1.5.2
        */

        /**
        * Get Result Of Last Query as an array
        * @since v1.5.2
        */
        public function getResult()
        {
            return $this->Result;
        }
        /**
        * Get Last Generated Global Array name for using in another query again.
        * @since v1.5.2
        */
        public function getArrayName()
        {
            return $this->Tokens[self::AR_INDEX];
        }

        /**
        * Array Rebuild Can redecorate the given array as tamplte you given . use array_map as template
        * @since v1.5.2
        */
        public function arrayRebuild(array $Array,$ForceArrayElement = False,$template = '$value = $value;$key = $key;')
        {
            $newarray = array();
            foreach ($Array AS $key=>$value)
            {
                if(!$ForceArrayElement)
                    eval($template);
                if(is_array($value))
                {
                    $value = self::arrayRebuild($value,false,$template);
                }
                if($ForceArrayElement)
                    eval($template);
                $newarray[is_array($key)?implode('|',$key):$key] = $value;
            }
            return $newarray;
        }
        /**
        * Unset Extracted Variables by Array
        * @param mixed $Array
        * @since v1.5.4
        */
        public function unsetByArray($Array)
        {
            return (is_array($Array) && !in_array(0,$Array)) ? 'unset($'.implode(',$',$Array).')' : '';
        }


        /**
        * print query result in a html table
        *
        * @param mixed $Array
        * @return d3Grid
        */
        public function grid($Array=false)
        {
            class_exists('D3Grid',true) || $this->Error('Class Not found: D3Grid');
            if (!is_a($this->grid,'D3Grid'))
            {
                if(!is_array($Array))
                    $Array = $this->fetch_all();

                if(is_Array($Array))
                {
                    $this->grid = new d3Grid($Array);
                }
                else
                    $this->Error('this is not an array for generate a grid');
            }
            else
            {
                if(is_array($Array))
                {
                    $this->grid = new d3Grid($Array);
                }
            }

            return $a=&$this->grid;
            return new d3Grid(array()); # IDE Hack
        }

    }
?>
Return current item: LINQ In PHP