Issues (2268)

htdocs/class/model/write.php (1 issue)

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
        $myts     = \MyTextSanitizer::getInstance();
46
        $errors = [];
47
48
        $vars              = $object->getVars();
49
        $object->cleanVars = [];
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']) {
75
                        $errors[] = sprintf(_XOBJ_ERR_SHORTERTHAN, $k, (int)$v['maxlength']);
76
                        continue 2;
77
                    }
78
79
                        $cleanv = $myts->censorString($cleanv);
80
81
                    $cleanv = str_replace('\\"', '"', $this->handler->db->quote($cleanv));
82
                    break;
83
84
                case XOBJ_DTYPE_UNICODE_TXTAREA:
85
                    if ($v['required'] && $cleanv != '0' && $cleanv == '') {
86
                        $errors[] = sprintf(_XOBJ_ERR_REQUIRED, $k);
87
                        continue 2;
88
                    }
89
                    $cleanv = xoops_convert_encode($cleanv);
90
                        $cleanv = $myts->censorString($cleanv);
91
92
                    $cleanv = str_replace('\\"', '"', $this->handler->db->quote($cleanv));
93
                    break;
94
95
                case XOBJ_DTYPE_TXTBOX:
96
                    if ($v['required'] && $cleanv != '0' && $cleanv == '') {
97
                        $errors[] = sprintf(_XOBJ_ERR_REQUIRED, $k);
98
                        continue 2;
99
                    }
100
                    if (isset($v['maxlength']) && strlen($cleanv) > (int)$v['maxlength']) {
101
                        $errors[] = sprintf(_XOBJ_ERR_SHORTERTHAN, $k, (int)$v['maxlength']);
102
                        continue 2;
103
                    }
104
105
                        $cleanv = $myts->censorString($cleanv);
106
                    $cleanv = str_replace('\\"', '"', $this->handler->db->quote($cleanv));
107
                    break;
108
109
                case XOBJ_DTYPE_TXTAREA:
110
                    if ($v['required'] && $cleanv != '0' && $cleanv == '') {
111
                        $errors[] = sprintf(_XOBJ_ERR_REQUIRED, $k);
112
                        continue 2;
113
                    }
114
115
                        $cleanv = $myts->censorString($cleanv);
116
                    $cleanv = str_replace('\\"', '"', $this->handler->db->quote($cleanv));
117
                    break;
118
119
                case XOBJ_DTYPE_SOURCE:
120
                    $cleanv = trim($cleanv);
121
                    $cleanv = str_replace('\\"', '"', $this->handler->db->quote($cleanv));
122
                    break;
123
                // Should not be used!
124
                case XOBJ_DTYPE_UNICODE_EMAIL:
125
                    $cleanv = trim($cleanv);
126
                    if ($v['required'] && $cleanv == '') {
127
                        $errors[] = sprintf(_XOBJ_ERR_REQUIRED, $k);
128
                        continue 2;
129
                    }
130
                    $cleanv = str_replace('\\"', '"', $this->handler->db->quote(xoops_convert_encode($cleanv)));
131
                    break;
132
133
                case XOBJ_DTYPE_EMAIL:
134
                    $cleanv = trim($cleanv);
135
                    if ($v['required'] && $cleanv == '') {
136
                        $errors[] = sprintf(_XOBJ_ERR_REQUIRED, $k);
137
                        continue 2;
138
                    }
139
                    if ($cleanv != '' && !preg_match("/^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+([\.][a-z0-9-]+)+$/i", $cleanv)) {
140
                        $errors[] = 'Invalid Email';
141
                        continue 2;
142
                    }
143
                    $cleanv = str_replace('\\"', '"', $this->handler->db->quote($cleanv));
144
                    break;
145
146
                // Should not be used!
147
                case XOBJ_DTYPE_UNICODE_URL:
148
                    $cleanv = trim($cleanv);
149
                    if ($v['required'] && $cleanv == '') {
150
                        $errors[] = sprintf(_XOBJ_ERR_REQUIRED, $k);
151
                        continue 2;
152
                    }
153
                    if ($cleanv != '' && !preg_match("/^http[s]*:\/\//i", $cleanv)) {
154
                        $cleanv = XOOPS_PROT . $cleanv;
155
                    }
156
                    $cleanv = str_replace('\\"', '"', $this->handler->db->quote(xoops_convert_encode($cleanv)));
157
                    break;
158
                case XOBJ_DTYPE_URL:
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("/^http[s]*:\/\//i", $cleanv)) {
165
                        $cleanv = XOOPS_PROT . $cleanv;
166
                    }
167
                    $cleanv = str_replace('\\"', '"', $this->handler->db->quote($cleanv));
168
                    break;
169
170
                // Should not be used!
171
                case XOBJ_DTYPE_UNICODE_OTHER:
172
                    $cleanv = str_replace('\\"', '"', $this->handler->db->quote(xoops_convert_encode($cleanv)));
173
                    break;
174
175
                case XOBJ_DTYPE_OTHER:
176
                    $cleanv = str_replace('\\"', '"', $this->handler->db->quote($cleanv));
177
                    break;
178
179
                case XOBJ_DTYPE_INT:
180
                    $cleanv = (int)$cleanv;
181
                    break;
182
183
                case XOBJ_DTYPE_FLOAT:
184
                    $cleanv = (float)$cleanv;
185
                    break;
186
187
                case XOBJ_DTYPE_DECIMAL:
188
                    $cleanv = (float)$cleanv;
189
                    break;
190
191
                // Should not be used!
192
                case XOBJ_DTYPE_UNICODE_ARRAY:
193
                    if (!$v['not_gpc']) {
194
                        $cleanv = array_map([&$myts, 'stripSlashesGPC'], $cleanv);
195
                    }
196
                    foreach (array_keys($cleanv) as $key) {
197
                        $cleanv[$key] = str_replace('\\"', '"', addslashes($cleanv[$key]));
198
                    }
199
                    // TODO: Not encoding safe, should try base64_encode -- phppp
200
                    $cleanv = "'" . serialize(array_walk($cleanv, 'xoops_aw_encode')) . "'";
201
                    break;
202
203
                case XOBJ_DTYPE_ARRAY:
204
                    $cleanv = (array)$cleanv;
205
                    if (!$v['not_gpc']) {
206
                        $cleanv = array_map([&$myts, 'stripSlashesGPC'], $cleanv);
207
                    }
208
                    // TODO: Not encoding safe, should try base64_encode -- phppp
209
                    $cleanv = $this->handler->db->quote(serialize($cleanv));
210
                    break;
211
212
                case XOBJ_DTYPE_STIME:
213
                case XOBJ_DTYPE_MTIME:
214
                case XOBJ_DTYPE_LTIME:
215
                    $cleanv = !is_string($cleanv) ? (int)$cleanv : strtotime($cleanv);
216
                    break;
217
218
                default:
219
                    $cleanv = str_replace('\\"', '"', $this->handler->db->quote($cleanv));
220
                    break;
221
            }
222
            $object->cleanVars[$k] = $cleanv;
223
        }
224
        if (!empty($errors)) {
225
            $object->setErrors($errors);
226
        }
227
        $object->unsetDirty();
228
229
        return empty($errors) ? true : false;
230
    }
231
232
    /**
233
     * insert an object into the database
234
     *
235
     * @param  object $object {@link XoopsObject} reference to object
236
     * @param  bool   $force  flag to force the query execution despite security settings
237
     * @return mixed  object ID
238
     */
239
    public function insert($object, $force = true)
240
    {
241
        if (!$object->isDirty()) {
242
            trigger_error("Data entry is not inserted - the object '" . get_class($object) . "' is not dirty", E_USER_NOTICE);
243
244
            return $object->getVar($this->handler->keyName);
245
        }
246
        if (!$this->cleanVars($object)) {
247
            trigger_error("Insert failed in method 'cleanVars' of object '" . get_class($object) . "'", E_USER_WARNING);
248
249
            return $object->getVar($this->handler->keyName);
250
        }
251
        $queryFunc = empty($force) ? 'query' : 'queryF';
252
253
        if ($object->isNew()) {
254
            $sql = 'INSERT INTO `' . $this->handler->table . '`';
255
            if (!empty($object->cleanVars)) {
256
                $keys = array_keys($object->cleanVars);
257
                $vals = array_values($object->cleanVars);
258
                $sql .= ' (`' . implode('`, `', $keys) . '`) VALUES (' . implode(',', $vals) . ')';
259
            } else {
260
                trigger_error("Data entry is not inserted - no variable is changed in object of '" . get_class($object) . "'", E_USER_NOTICE);
261
262
                return $object->getVar($this->handler->keyName);
263
            }
264
            if (!$result = $this->handler->db->{$queryFunc}($sql)) {
265
                return false;
266
            }
267
            if (!$object->getVar($this->handler->keyName) && $object_id = $this->handler->db->getInsertId()) {
268
                $object->assignVar($this->handler->keyName, $object_id);
269
            }
270
        } elseif (!empty($object->cleanVars)) {
271
            $keys = [];
272
            foreach ($object->cleanVars as $k => $v) {
273
                $keys[] = " `{$k}` = {$v}";
274
            }
275
            $sql = 'UPDATE `' . $this->handler->table . '` SET ' . implode(',', $keys) . ' WHERE `' . $this->handler->keyName . '` = ' . $this->handler->db->quote($object->getVar($this->handler->keyName));
276
            if (!$result = $this->handler->db->{$queryFunc}($sql)) {
277
                return false;
278
            }
279
        }
280
281
        return $object->getVar($this->handler->keyName);
282
    }
283
284
    /**
285
     * delete an object from the database
286
     *
287
     * @param  object $object {@link XoopsObject} reference to the object to delete
288
     * @param  bool   $force
289
     * @return bool   FALSE if failed.
290
     */
291
    public function delete($object, $force = false)
292
    {
293
        if (is_array($this->handler->keyName)) {
294
            $clause = [];
295
            $thishandlerkeyNameCount = count($this->handler->keyName);
296
            for ($i = 0; $i < $thishandlerkeyNameCount; ++$i) {
297
                $clause[] = '`' . $this->handler->keyName[$i] . '` = ' . $this->handler->db->quote($object->getVar($this->handler->keyName[$i]));
298
            }
299
            $whereclause = implode(' AND ', $clause);
300
        } else {
301
            $whereclause = '`' . $this->handler->keyName . '` = ' . $this->handler->db->quote($object->getVar($this->handler->keyName));
302
        }
303
        $sql       = 'DELETE FROM `' . $this->handler->table . '` WHERE ' . $whereclause;
304
        $queryFunc = empty($force) ? 'query' : 'queryF';
305
        $result    = $this->handler->db->{$queryFunc}($sql);
306
307
        return empty($result) ? false : true;
308
    }
309
310
    /**
311
     * delete all objects matching the conditions
312
     *
313
     * @param  CriteriaElement|CriteriaCompo $criteria {@link CriteriaElement} with conditions to meet
314
     * @param  bool   $force    force to delete
315
     * @param  bool   $asObject delete in object way: instantiate all objects and delete one by one
316
     * @return bool|int
317
     */
318
    public function deleteAll(?CriteriaElement $criteria = null, $force = true, $asObject = false)
319
    {
320
        if ($asObject) {
321
            $objects = $this->handler->getAll($criteria);
322
            $num     = 0;
323
            foreach (array_keys($objects) as $key) {
324
                $num += $this->delete($objects[$key], $force) ? 1 : 0;
325
            }
326
            unset($objects);
327
328
            return $num;
329
        }
330
        $queryFunc = empty($force) ? 'query' : 'queryF';
331
        $sql       = 'DELETE FROM ' . $this->handler->table;
332
        if (!empty($criteria)) {
333
            if (is_subclass_of($criteria, 'CriteriaElement')) {
334
                $sql .= ' ' . $criteria->renderWhere();
0 ignored issues
show
The method renderWhere() does not exist on CriteriaElement. Did you maybe mean render()? ( Ignorable by Annotation )

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

334
                $sql .= ' ' . $criteria->/** @scrutinizer ignore-call */ renderWhere();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
335
            } else {
336
                return false;
337
            }
338
        }
339
        if (!$this->handler->db->{$queryFunc}($sql)) {
340
            return false;
341
        }
342
343
        return $this->handler->db->getAffectedRows();
344
    }
345
346
    /**
347
     * Change a field for objects with a certain criteria
348
     *
349
     * @param  string $fieldname  Name of the field
350
     * @param  mixed  $fieldvalue Value to write
351
     * @param  CriteriaElement|CriteriaCompo  $criteria   {@link CriteriaElement}
352
     * @param  bool   $force      force to query
353
     * @return bool
354
     */
355
    public function updateAll($fieldname, $fieldvalue, ?CriteriaElement $criteria = null, $force = false)
356
    {
357
        $set_clause = "`{$fieldname}` = ";
358
        if (is_numeric($fieldvalue)) {
359
            $set_clause .= $fieldvalue;
360
        } elseif (is_array($fieldvalue)) {
361
            $set_clause .= $this->handler->db->quote(implode(',', $fieldvalue));
362
        } else {
363
            $set_clause .= $this->handler->db->quote($fieldvalue);
364
        }
365
        $sql = 'UPDATE `' . $this->handler->table . '` SET ' . $set_clause;
366
        if (isset($criteria) && \method_exists($criteria, 'renderWhere')) {
367
            $sql .= ' ' . $criteria->renderWhere();
368
        }
369
        $queryFunc = empty($force) ? 'query' : 'queryF';
370
        $result    = $this->handler->db->{$queryFunc}($sql);
371
372
        return empty($result) ? false : true;
373
    }
374
}
375