source: branches/2.2/workflow/inc/engine/src/common/Base.php @ 3167

Revision 3167, 11.0 KB checked in by viani, 14 years ago (diff)

Ticket #1135 - Merged r1990:3166 from /trunk/workflow into /branches/2.2/workflow

  • Property svn:executable set to *
Line 
1<?php
2/**
3 * This class is derived by all the API classes so they get the
4 * database connection and the database methods.
5 *
6 * @package Galaxia
7 * @license http://www.gnu.org/copyleft/gpl.html GPL
8 */
9class Base {
10        /**
11         * @var object $db Database abstraction object used to access the database
12         * @access public
13         */
14        var $db;
15        /**
16         * @var int     $num_queries Debugging var
17         * @access private
18         */
19        var $num_queries = 0;
20        /**
21         * @var int     $num_queries_total Debugging var
22         * @access private
23         */
24        var $num_queries_total = 0;
25        /**
26         * @var array  $error Error messages
27         * @access public
28         */
29        var $error= Array();
30        /**
31         * @var array $warning Warning messages
32         * @access public
33         */
34        var $warning = array();
35        /**
36         * @var string $child_name Name of the current object
37         * @access public
38         */
39        var $child_name = 'Base';
40
41        /**
42         * @var object $db_shared_obj The database abstraction object shared between
43         *                                                    all instances of this class.
44         * @acess private
45         * @static
46         */
47        private static $db_shared_obj = null;
48
49  /**
50   * Constructor receiving a database abstraction object
51   * @package Galaxia
52   * @param object &$db ADOdb
53   * @return object Base instance
54   * @access public
55   */
56  function Base()
57  {
58        /**
59         * New Stuff!
60         * We decided to get here the database object. In a recent past,
61         * all the classes that specialize this one passed a db object.
62         * Now, to simplify and save memory, we store the database object
63         * into a single and static atribute shared among each instance
64         * of this class.
65         *
66         * To prevent to modify all sub-classes to use "self::$db" instead
67         * of "this->db", we made a very tiny workaround here. In the first
68         * instantiation of this class, we instantiate the database object
69         * and store it into 'self::$db_shared_obj'. Any subsequent
70         * instantiations will just point to the static one.
71         */
72        if (!self::$db_shared_obj)
73                self::$db_shared_obj = &Factory::getInstance('WorkflowObjects')->getDBGalaxia()->Link_ID;
74
75        $this->db = &self::$db_shared_obj;
76
77
78    if(!$this->db) {
79      die('Invalid db object passed to '.$this->child_name.' constructor');
80    }
81    //Force transactionnal mysql (Innodb) -> mysqlt
82    if ($this->db->databaseType=='mysql')
83    {
84        $GLOBALS['phpgw']->db->disconnect();
85        $this->db = $GLOBALS['phpgw']->db->connect(
86                        $GLOBALS['phpgw_info']['server']['db_name'],
87                        $GLOBALS['phpgw_info']['server']['db_host'],
88                        $GLOBALS['phpgw_info']['server']['db_port'],
89                        $GLOBALS['phpgw_info']['server']['db_user'],
90                        $GLOBALS['phpgw_info']['server']['db_pass'],
91                        'mysqlt'
92                );
93    }
94  }
95
96  /**
97   * Gets errors recorded by this object
98   * Always call this function after failed operations on a workflow object to obtain messages
99   *
100   * @param bool $as_array if true the result will be send as an array of errors or an empty array. Else, if you do not give any parameter
101   * or give a false parameter you will obtain a single string which can be empty or will contain error messages with <br /> html tags
102   * @param bool $debug is false by default, if true you wil obtain more messages
103   * @param string $prefix string appended to the debug message
104   * @return mixed Error and debug messages or an array of theses messages and empty the error messages
105   * @access public
106   */
107  function get_error($as_array=false, $debug=false, $prefix='')
108  {
109    //collect errors from used objects
110    $this->collect_errors($debug, $prefix.$this->child_name.'::');
111    if ($as_array)
112    {
113      $result = $this->error;
114      $this->error= Array();
115      return $result;
116    }
117    $result_str = implode('<br />',array_filter($this->error));
118    $this->error= Array();
119    return $result_str;
120  }
121
122  /**
123   * Gets warnings recorded by this object
124   *
125   * @param bool $as_array if true the result will be send as an array of warnings or an empty array. Else, if you do not give any parameter
126   * or give a false parameter you will obtain a single string which can be empty or will contain warning messages with <br /> html tags
127   * @return mixed Warning messages or an array of theses messages and empty the warning messages
128   * @access public
129   */
130  function get_warning($as_array=false)
131  {
132    if ($as_array)
133    {
134      $result = $this->warning;
135      $this->warning= Array();
136      return $result;
137    }
138    $result_str = implode('<br />',array_filter($this->warning));
139    $this->warning= Array();
140    return $result_str;
141  }
142
143  /**
144   * Collect errors from all linked objects which could have been used by this object
145   * Each child class should instantiate this function with her linked objetcs, calling get_error(true)
146   *
147   * @param bool $debug is false by default, if true debug messages can be added to 'normal' messages
148   * @param string $prefix is a string appended to the debug message
149   * @abstract
150   * @access public
151   * @return void
152   */
153  function collect_errors($debug=false, $prefix = '')
154  {
155        if ($debug)
156        {
157                $this->num_queries_total += $this->num_queries;
158                $this->error[] = $prefix.': number of queries: new='.$this->num_queries.'/ total='.$this->num_queries_total;
159                $this->num_queries = 0;
160        }
161  }
162
163        /**
164         * Performs a query on the AdoDB database object
165         *
166         * @param string $query sql query, parameters should be replaced with ?
167         * @param array $values array containing the parameters (going in the ?), use it to avoid security problems. If
168         * one of theses values is an array it will be serialized and encoded in Base64
169         * @param int $numrows maximum number of rows to return
170         * @param int $offset starting row number
171         * @param bool $reporterrors is true by default, if false no warning will be generated in the php log
172         * @param string $sort is the sort sql string for the query (without the "order by ")
173         * @param bool $bulk is false by default, if true the $values array parameters could contain arrays vars for bulk statement
174         * (see ADOdb help) theses arrays wont be serialized and encoded in Base64 like current arrays parameters,
175         * it will be checked for security reasons before being appended to the sql
176         * @return mixed false if something went wrong or the resulting recordset array if it was ok
177         * @access public
178         */
179        function query($query, $values = null, $numrows = -1, $offset = -1, $reporterrors = true, $sort='', $bulk=false)
180        {
181                //clean the parameters
182                $clean_values = Array();
183                if (!($values===null))
184                {
185                        if (!(is_array($values)))
186                        {
187                                $values= array($values);
188                        }
189                        foreach($values as $value)
190                        {
191                                $clean_values[] = $this->security_cleanup($value, !($bulk));
192                        }
193                }
194                //clean sort order as well and add it to the query
195                if (!(empty($sort)))
196                {
197                        $sort = $this->security_cleanup($sort, true, true);
198                        $query .= " order by $sort";
199                }
200
201
202                //conversion must be done after oder by is set
203                $this->convert_query($query);
204                // Galaxia needs to be call ADOdb in associative mode
205                $this->db->SetFetchMode(ADODB_FETCH_ASSOC);
206                if ($numrows == -1 && $offset == -1)
207                        $result = $this->db->Execute($query, $clean_values);
208                else
209                        $result = $this->db->SelectLimit($query, $numrows, $offset, $clean_values);
210                if (empty($result))
211                {
212                        $result = false;
213                }
214                $this->num_queries++;
215                if (!$result)
216                {
217                        $this->error[] = "there were some SQL errors in the database, please warn your sysadmin.";
218                        if ($reporterrors) $this->sql_error($query, $clean_values, $result);
219                }
220                return $result;
221        }
222
223        /**
224         * @see Base::query
225         * @param string $query sql query, parameters should be replaced with ?
226     * @param array $values array containing the parameters (going in the ?), use it to avoid security problems
227         * @param bool $reporterrors is true by default, if false no warning will be generated in the php log
228         * @return mixed NULL if something went wrong or the first value of the first row if it was ok
229         * @access public
230         */
231        function getOne($query, $values = null, $reporterrors = true) {
232                $this->convert_query($query);
233                $clean_values = Array();
234                if (!($values===null))
235                {
236                        if (!(is_array($values)))
237                        {
238                                $values= array($values);
239                        }
240                        foreach($values as $value)
241                        {
242                                $clean_values[] = $this->security_cleanup($value);
243                        }
244                }
245                $result = $this->db->SelectLimit($query, 1, 0, $clean_values);
246                if (empty($result))
247                {
248                        $result = false;
249                }
250                if (!$result && $reporterrors )
251                        $this->sql_error($query, $clean_values, $result);
252                if (!!$result)
253                {
254                        $res = $result->fetchRow();
255                }
256                else
257                {
258                        $res = false;
259                }
260                $this->num_queries++;
261                if ($res === false)
262                        return (NULL); //simulate pears behaviour
263                list($key, $value) = each($res);
264                return $value;
265        }
266
267        /**
268         * Throws error warnings
269         *
270         * @param string $query
271         * @param array $values
272         * @param mixed $result
273         * @access public
274         * @return void
275         */
276        function sql_error($query, $values, $result) {
277                trigger_error($this->db->databaseType . " error:  " . $this->db->ErrorMsg(). " in query:<br/>" . $query . "<br/>", E_USER_WARNING);
278                // DO NOT DIE, if transactions are there, they will do things in a better way
279        }
280
281        /**
282         * Clean the data before it is recorded on the database
283         *
284         * @param $value is a data we want to be stored in the database.
285         * If it is an array we'll make a serialize and then an base64_encode
286         * (you'll have to make an unserialize(base64_decode())
287         * If it is not an array we make an htmlspecialchars() on it
288         * @param bool $flat_arrays is true by default, if false arrays won't be serialized and encoded
289         * @param bool $check_for_injection is false by default, if true we'll perform some modifications
290         * on the string to avoid SQL injection
291         * @return mixed @access public
292         */
293        function security_cleanup($value, $flat_arrays = true, $check_for_injection = false)
294        {
295                if (is_array($value))
296                {
297                        if ($flat_arrays) {
298                                //serialize and \' are a big #!%*
299                                $res = base64_encode(serialize($value));
300                        }
301                        else
302                        {
303                                //recursive cleanup on the array
304                                $res = Array();
305                                foreach ($value as $key => $item)
306                                {
307                                        $res[$this->security_cleanup($key,$flat_arrays)] = $this->security_cleanup($item, $flat_arrays);
308                                }
309                        }
310                }
311                else
312                {
313                        $res = ($check_for_injection)? addslashes(str_replace(';','',$value)) : $value;
314                }
315                return $res;
316        }
317
318        /**
319         * Supports DB abstraction
320         *
321         * @param string &$query
322         * @return void
323         * @access public
324         */
325        function convert_query(&$query) {
326
327                switch ($this->db->databaseType) {
328                case "oci8":
329                        $query = preg_replace("/`/", "\"", $query);
330                        // convert bind variables - adodb does not do that
331                        $qe = explode("?", $query);
332                        $query = '';
333                        for ($i = 0; $i < sizeof($qe) - 1; $i++) {
334                                $query .= $qe[$i] . ":" . $i;
335                        }
336                        $query .= $qe[$i];
337                        break;
338                case "postgres7":
339                case "sybase":
340                        $query = preg_replace("/`/", "\"", $query);
341                        break;
342                }
343        }
344        /**
345         * Supports DB abstraction
346         *
347         * @param string $sort_mode
348         * @return string
349         * @access public
350         */
351        function convert_sortmode($sort_mode) {
352                $sort_mode = str_replace("__", "` ", $sort_mode);
353                $sort_mode = "`" . $sort_mode;
354                return $sort_mode;
355        }
356        /**
357         * Supports DB abstraction
358         *
359         * @return mixed
360         * @access public
361         */
362        function convert_binary() {
363
364                switch ($this->db->databaseType) {
365                case "pgsql72":
366                case "oci8":
367                case "postgres7":
368                        return;
369                        break;
370                case "mysql3":
371                case "mysql":
372                        return "binary";
373                        break;
374                }
375        }
376
377}
378?>
Note: See TracBrowser for help on using the repository browser.