Completed
Push — master ( 7bb5bf...9a4e50 )
by Richard
28:24 queued 22s
created

htdocs/class/model/write.php (2 issues)

1
<?php
2
/**
3
 * Object write handler class.
4
 *
5
 * You may not change or alter any portion of this comment or credits
6
 * of supporting developers from this source code or any supporting source code
7
 * which is considered copyrighted (c) material of the original comment or credit authors.
8
 * This program is distributed in the hope that it will be useful,
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11
 *
12
 * @copyright       (c) 2000-2016 XOOPS Project (www.xoops.org)
13
 * @license             GNU GPL 2 (https://www.gnu.org/licenses/gpl-2.0.html)
14
 * @package             kernel
15
 * @subpackage          model
16
 * @since               2.3.0
17
 * @author              Taiwen Jiang <[email protected]>
18
 */
19
defined('XOOPS_ROOT_PATH') || exit('Restricted access');
20
21
/**
22
 * Object write handler class.
23
 *
24
 * @author Taiwen Jiang <[email protected]>
25
 * @author Simon Roberts <[email protected]>
26
 *
27
 * {@link XoopsModelAbstract}
28
 */
29
class XoopsModelWrite extends XoopsModelAbstract
30
{
31
    /**
32
     * Clean values of all variables of the object for storage.
33
     * also add slashes and quote string wherever needed
34
     *
35
     * CleanVars only contains changed and cleaned variables
36
     * Reference is used for PHP4 compliance
37
     *
38
     * @param $object
39
     *
40
     * @return bool true if successful
41
     * @access public
42
     */
43
    public function cleanVars(&$object)
44
    {
45
        $ts     = MyTextSanitizer::getInstance();
46
        $errors = array();
47
48
        $vars              = $object->getVars();
49
        $object->cleanVars = array();
50
        foreach ($vars as $k => $v) {
51
            if (!$v['changed']) {
52
                continue;
53
            }
54
            $cleanv = $v['value'];
55
            switch ($v['data_type']) {
56
                case XOBJ_DTYPE_TIMESTAMP:
57
                    $cleanv = !is_string($cleanv) && is_numeric($cleanv) ? date(_DBTIMESTAMPSTRING, $cleanv) : date(_DBTIMESTAMPSTRING, strtotime($cleanv));
58
                    $cleanv = str_replace('\\"', '"', $this->handler->db->quote($cleanv));
59
                    break;
60
                case XOBJ_DTYPE_TIME:
61
                    $cleanv = !is_string($cleanv) && is_numeric($cleanv) ? date(_DBTIMESTRING, $cleanv) : date(_DBTIMESTRING, strtotime($cleanv));
62
                    $cleanv = str_replace('\\"', '"', $this->handler->db->quote($cleanv));
63
                    break;
64
                case XOBJ_DTYPE_DATE:
65
                    $cleanv = !is_string($cleanv) && is_numeric($cleanv) ? date(_DBDATESTRING, $cleanv) : date(_DBDATESTRING, strtotime($cleanv));
66
                    $cleanv = str_replace('\\"', '"', $this->handler->db->quote($cleanv));
67
                    break;
68
                case XOBJ_DTYPE_UNICODE_TXTBOX:
69
                    if ($v['required'] && $cleanv != '0' && $cleanv == '') {
70
                        $errors[] = sprintf(_XOBJ_ERR_REQUIRED, $k);
71
                        continue 2;
72
                    }
73
                    $cleanv = xoops_convert_encode($cleanv);
74
                    if (isset($v['maxlength']) && strlen($cleanv) > (int)$v['maxlength']) {
0 ignored issues
show
$cleanv of type boolean is incompatible with the type string expected by parameter $string of strlen(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

74
                    if (isset($v['maxlength']) && strlen(/** @scrutinizer ignore-type */ $cleanv) > (int)$v['maxlength']) {
Loading history...
75
                        $errors[] = sprintf(_XOBJ_ERR_SHORTERTHAN, $k, (int)$v['maxlength']);
76
                        continue 2;
77
                    }
78
                    if (!$v['not_gpc']) {
79
                        $cleanv = $ts->stripSlashesGPC($ts->censorString($cleanv));
80
                    } else {
81
                        $cleanv = $ts->censorString($cleanv);
82
                    }
83
                    $cleanv = str_replace('\\"', '"', $this->handler->db->quote($cleanv));
84
                    break;
85
86
                case XOBJ_DTYPE_UNICODE_TXTAREA:
87
                    if ($v['required'] && $cleanv != '0' && $cleanv == '') {
88
                        $errors[] = sprintf(_XOBJ_ERR_REQUIRED, $k);
89
                        continue 2;
90
                    }
91
                    $cleanv = xoops_convert_encode($cleanv);
92
                    if (!$v['not_gpc']) {
93
                        if (!empty($vars['dohtml']['value'])) {
94
                            $cleanv = $ts->textFilter($cleanv);
95
                        }
96
                        $cleanv = $ts->stripSlashesGPC($ts->censorString($cleanv));
97
                    } else {
98
                        $cleanv = $ts->censorString($cleanv);
99
                    }
100
                    $cleanv = str_replace('\\"', '"', $this->handler->db->quote($cleanv));
101
                    break;
102
103
                case XOBJ_DTYPE_TXTBOX:
104
                    if ($v['required'] && $cleanv != '0' && $cleanv == '') {
105
                        $errors[] = sprintf(_XOBJ_ERR_REQUIRED, $k);
106
                        continue 2;
107
                    }
108
                    if (isset($v['maxlength']) && strlen($cleanv) > (int)$v['maxlength']) {
109
                        $errors[] = sprintf(_XOBJ_ERR_SHORTERTHAN, $k, (int)$v['maxlength']);
110
                        continue 2;
111
                    }
112
                    if (!$v['not_gpc']) {
113
                        $cleanv = $ts->stripSlashesGPC($ts->censorString($cleanv));
114
                    } else {
115
                        $cleanv = $ts->censorString($cleanv);
116
                    }
117
                    $cleanv = str_replace('\\"', '"', $this->handler->db->quote($cleanv));
118
                    break;
119
120
                case XOBJ_DTYPE_TXTAREA:
121
                    if ($v['required'] && $cleanv != '0' && $cleanv == '') {
122
                        $errors[] = sprintf(_XOBJ_ERR_REQUIRED, $k);
123
                        continue 2;
124
                    }
125
                    if (!$v['not_gpc']) {
126
                        if (!empty($vars['dohtml']['value'])) {
127
                            $cleanv = $ts->textFilter($cleanv);
128
                        }
129
                        $cleanv = $ts->stripSlashesGPC($ts->censorString($cleanv));
130
                    } else {
131
                        $cleanv = $ts->censorString($cleanv);
132
                    }
133
                    $cleanv = str_replace('\\"', '"', $this->handler->db->quote($cleanv));
134
                    break;
135
136
                case XOBJ_DTYPE_SOURCE:
137
                    $cleanv = trim($cleanv);
138
                    if (!$v['not_gpc']) {
139
                        $cleanv = $ts->stripSlashesGPC($cleanv);
140
                    } else {
141
                        $cleanv = $cleanv;
142
                    }
143
                    $cleanv = str_replace('\\"', '"', $this->handler->db->quote($cleanv));
144
                    break;
145
                // Should not be used!
146
                case XOBJ_DTYPE_UNICODE_EMAIL:
147
                    $cleanv = trim($cleanv);
148
                    if ($v['required'] && $cleanv == '') {
149
                        $errors[] = sprintf(_XOBJ_ERR_REQUIRED, $k);
150
                        continue 2;
151
                    }
152
                    if (!$v['not_gpc']) {
153
                        $cleanv = $ts->stripSlashesGPC($cleanv);
154
                    }
155
                    $cleanv = str_replace('\\"', '"', $this->handler->db->quote(xoops_convert_encode($cleanv)));
156
                    break;
157
158
                case XOBJ_DTYPE_EMAIL:
159
                    $cleanv = trim($cleanv);
160
                    if ($v['required'] && $cleanv == '') {
161
                        $errors[] = sprintf(_XOBJ_ERR_REQUIRED, $k);
162
                        continue 2;
163
                    }
164
                    if ($cleanv != '' && !preg_match("/^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+([\.][a-z0-9-]+)+$/i", $cleanv)) {
165
                        $errors[] = 'Invalid Email';
166
                        continue 2;
167
                    }
168
                    if (!$v['not_gpc']) {
169
                        $cleanv = $ts->stripSlashesGPC($cleanv);
170
                    }
171
                    $cleanv = str_replace('\\"', '"', $this->handler->db->quote($cleanv));
172
                    break;
173
174
                // Should not be used!
175
                case XOBJ_DTYPE_UNICODE_URL:
176
                    $cleanv = trim($cleanv);
177
                    if ($v['required'] && $cleanv == '') {
178
                        $errors[] = sprintf(_XOBJ_ERR_REQUIRED, $k);
179
                        continue 2;
180
                    }
181
                    if ($cleanv != '' && !preg_match("/^http[s]*:\/\//i", $cleanv)) {
182
                        $cleanv = XOOPS_PROT . $cleanv;
183
                    }
184
                    if (!$v['not_gpc']) {
185
                        $cleanv = $ts->stripSlashesGPC($cleanv);
186
                    }
187
                    $cleanv = str_replace('\\"', '"', $this->handler->db->quote(xoops_convert_encode($cleanv)));
188
                    break;
189
                case XOBJ_DTYPE_URL:
190
                    $cleanv = trim($cleanv);
191
                    if ($v['required'] && $cleanv == '') {
192
                        $errors[] = sprintf(_XOBJ_ERR_REQUIRED, $k);
193
                        continue 2;
194
                    }
195
                    if ($cleanv != '' && !preg_match("/^http[s]*:\/\//i", $cleanv)) {
196
                        $cleanv = XOOPS_PROT . $cleanv;
197
                    }
198
                    if (!$v['not_gpc']) {
199
                        $cleanv = $ts->stripSlashesGPC($cleanv);
200
                    }
201
                    $cleanv = str_replace('\\"', '"', $this->handler->db->quote($cleanv));
202
                    break;
203
204
                // Should not be used!
205
                case XOBJ_DTYPE_UNICODE_OTHER:
206
                    $cleanv = str_replace('\\"', '"', $this->handler->db->quote(xoops_convert_encode($cleanv)));
207
                    break;
208
209
                case XOBJ_DTYPE_OTHER:
210
                    $cleanv = str_replace('\\"', '"', $this->handler->db->quote($cleanv));
211
                    break;
212
213
                case XOBJ_DTYPE_INT:
214
                    $cleanv = (int)$cleanv;
215
                    break;
216
217
                case XOBJ_DTYPE_FLOAT:
218
                    $cleanv = (float)$cleanv;
219
                    break;
220
221
                case XOBJ_DTYPE_DECIMAL:
222
                    $cleanv = (float)$cleanv;
223
                    break;
224
225
                // Should not be used!
226
                case XOBJ_DTYPE_UNICODE_ARRAY:
227
                    if (!$v['not_gpc']) {
228
                        $cleanv = array_map(array(&$ts, 'stripSlashesGPC'), $cleanv);
229
                    }
230
                    foreach (array_keys($cleanv) as $key) {
231
                        $cleanv[$key] = str_replace('\\"', '"', addslashes($cleanv[$key]));
232
                    }
233
                    // TODO: Not encoding safe, should try base64_encode -- phppp
234
                    $cleanv = "'" . serialize(array_walk($cleanv, 'xoops_aw_encode')) . "'";
235
                    break;
236
237
                case XOBJ_DTYPE_ARRAY:
238
                    $cleanv = (array)$cleanv;
239
                    if (!$v['not_gpc']) {
240
                        $cleanv = array_map(array(&$ts, 'stripSlashesGPC'), $cleanv);
241
                    }
242
                    // TODO: Not encoding safe, should try base64_encode -- phppp
243
                    $cleanv = $this->handler->db->quote(serialize($cleanv));
244
                    break;
245
246
                case XOBJ_DTYPE_STIME:
247
                case XOBJ_DTYPE_MTIME:
248
                case XOBJ_DTYPE_LTIME:
249
                    $cleanv = !is_string($cleanv) ? (int)$cleanv : strtotime($cleanv);
250
                    break;
251
252
                default:
253
                    $cleanv = str_replace('\\"', '"', $this->handler->db->quote($cleanv));
254
                    break;
255
            }
256
            $object->cleanVars[$k] = $cleanv;
257
        }
258
        if (!empty($errors)) {
259
            $object->setErrors($errors);
260
        }
261
        $object->unsetDirty();
262
263
        return empty($errors) ? true : false;
264
    }
265
266
    /**
267
     * insert an object into the database
268
     *
269
     * @param  object $object {@link XoopsObject} reference to object
270
     * @param  bool   $force  flag to force the query execution despite security settings
271
     * @return mixed  object ID
272
     */
273
    public function insert(&$object, $force = true)
274
    {
275
        if (!$object->isDirty()) {
276
            trigger_error("Data entry is not inserted - the object '" . get_class($object) . "' is not dirty", E_USER_NOTICE);
277
278
            return $object->getVar($this->handler->keyName);
279
        }
280
        if (!$this->cleanVars($object)) {
281
            trigger_error("Insert failed in method 'cleanVars' of object '" . get_class($object) . "'", E_USER_WARNING);
282
283
            return $object->getVar($this->handler->keyName);
284
        }
285
        $queryFunc = empty($force) ? 'query' : 'queryF';
286
287
        if ($object->isNew()) {
288
            $sql = 'INSERT INTO `' . $this->handler->table . '`';
289
            if (!empty($object->cleanVars)) {
290
                $keys = array_keys($object->cleanVars);
291
                $vals = array_values($object->cleanVars);
292
                $sql .= ' (`' . implode('`, `', $keys) . '`) VALUES (' . implode(',', $vals) . ')';
293
            } else {
294
                trigger_error("Data entry is not inserted - no variable is changed in object of '" . get_class($object) . "'", E_USER_NOTICE);
295
296
                return $object->getVar($this->handler->keyName);
297
            }
298
            if (!$result = $this->handler->db->{$queryFunc}($sql)) {
299
                return false;
300
            }
301
            if (!$object->getVar($this->handler->keyName) && $object_id = $this->handler->db->getInsertId()) {
302
                $object->assignVar($this->handler->keyName, $object_id);
303
            }
304
        } elseif (!empty($object->cleanVars)) {
305
            $keys = array();
306
            foreach ($object->cleanVars as $k => $v) {
307
                $keys[] = " `{$k}` = {$v}";
308
            }
309
            $sql = 'UPDATE `' . $this->handler->table . '` SET ' . implode(',', $keys) . ' WHERE `' . $this->handler->keyName . '` = ' . $this->handler->db->quote($object->getVar($this->handler->keyName));
310
            if (!$result = $this->handler->db->{$queryFunc}($sql)) {
311
                return false;
312
            }
313
        }
314
315
        return $object->getVar($this->handler->keyName);
316
    }
317
318
    /**
319
     * delete an object from the database
320
     *
321
     * @param  object $object {@link XoopsObject} reference to the object to delete
322
     * @param  bool   $force
323
     * @return bool   FALSE if failed.
324
     */
325
    public function delete(&$object, $force = false)
326
    {
327
        if (is_array($this->handler->keyName)) {
328
            $clause = array();
329
            $thishandlerkeyNameCount = count($this->handler->keyName);
330
            for ($i = 0; $i < $thishandlerkeyNameCount; ++$i) {
331
                $clause[] = '`' . $this->handler->keyName[$i] . '` = ' . $this->handler->db->quote($object->getVar($this->handler->keyName[$i]));
332
            }
333
            $whereclause = implode(' AND ', $clause);
334
        } else {
335
            $whereclause = '`' . $this->handler->keyName . '` = ' . $this->handler->db->quote($object->getVar($this->handler->keyName));
336
        }
337
        $sql       = 'DELETE FROM `' . $this->handler->table . '` WHERE ' . $whereclause;
338
        $queryFunc = empty($force) ? 'query' : 'queryF';
339
        $result    = $this->handler->db->{$queryFunc}($sql);
340
341
        return empty($result) ? false : true;
342
    }
343
344
    /**
345
     * delete all objects matching the conditions
346
     *
347
     * @param  CriteriaElement|CriteriaCompo $criteria {@link CriteriaElement} with conditions to meet
348
     * @param  bool   $force    force to delete
349
     * @param  bool   $asObject delete in object way: instantiate all objects and delete one by one
350
     * @return bool
351
     */
352
    public function deleteAll(CriteriaElement $criteria = null, $force = true, $asObject = false)
353
    {
354
        if ($asObject) {
355
            $objects = $this->handler->getAll($criteria);
356
            $num     = 0;
357
            foreach (array_keys($objects) as $key) {
358
                $num += $this->delete($objects[$key], $force) ? 1 : 0;
359
            }
360
            unset($objects);
361
362
            return $num;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $num returns the type integer which is incompatible with the documented return type boolean.
Loading history...
363
        }
364
        $queryFunc = empty($force) ? 'query' : 'queryF';
365
        $sql       = 'DELETE FROM ' . $this->handler->table;
366
        if (!empty($criteria)) {
367
            if (is_subclass_of($criteria, 'CriteriaElement')) {
368
                $sql .= ' ' . $criteria->renderWhere();
369
            } else {
370
                return false;
371
            }
372
        }
373
        if (!$this->handler->db->{$queryFunc}($sql)) {
374
            return false;
375
        }
376
377
        return $this->handler->db->getAffectedRows();
378
    }
379
380
    /**
381
     * Change a field for objects with a certain criteria
382
     *
383
     * @param  string $fieldname  Name of the field
384
     * @param  mixed  $fieldvalue Value to write
385
     * @param  CriteriaElement|CriteriaCompo  $criteria   {@link CriteriaElement}
386
     * @param  bool   $force      force to query
387
     * @return bool
388
     */
389
    public function updateAll($fieldname, $fieldvalue, CriteriaElement $criteria = null, $force = false)
390
    {
391
        $set_clause = "`{$fieldname}` = ";
392
        if (is_numeric($fieldvalue)) {
393
            $set_clause .= $fieldvalue;
394
        } elseif (is_array($fieldvalue)) {
395
            $set_clause .= $this->handler->db->quote(implode(',', $fieldvalue));
396
        } else {
397
            $set_clause .= $this->handler->db->quote($fieldvalue);
398
        }
399
        $sql = 'UPDATE `' . $this->handler->table . '` SET ' . $set_clause;
400
        if (isset($criteria) && is_subclass_of($criteria, 'CriteriaElement')) {
401
            $sql .= ' ' . $criteria->renderWhere();
402
        }
403
        $queryFunc = empty($force) ? 'query' : 'queryF';
404
        $result    = $this->handler->db->{$queryFunc}($sql);
405
406
        return empty($result) ? false : true;
407
    }
408
}
409