1 | <?php |
---|
2 | /*********************************************** |
---|
3 | * File : syncobjects.php |
---|
4 | * Project : Z-Push |
---|
5 | * Descr : Defines general behavoir of sub-WBXML |
---|
6 | * entities (Sync* objects) that can be parsed |
---|
7 | * directly (as a stream) from WBXML. |
---|
8 | * They are automatically decoded |
---|
9 | * according to $mapping by the Streamer, |
---|
10 | * and the Sync WBXML mappings. |
---|
11 | * |
---|
12 | * Created : 01.10.2007 |
---|
13 | * |
---|
14 | * Copyright 2007 - 2012 Zarafa Deutschland GmbH |
---|
15 | * |
---|
16 | * This program is free software: you can redistribute it and/or modify |
---|
17 | * it under the terms of the GNU Affero General Public License, version 3, |
---|
18 | * as published by the Free Software Foundation with the following additional |
---|
19 | * term according to sec. 7: |
---|
20 | * |
---|
21 | * According to sec. 7 of the GNU Affero General Public License, version 3, |
---|
22 | * the terms of the AGPL are supplemented with the following terms: |
---|
23 | * |
---|
24 | * "Zarafa" is a registered trademark of Zarafa B.V. |
---|
25 | * "Z-Push" is a registered trademark of Zarafa Deutschland GmbH |
---|
26 | * The licensing of the Program under the AGPL does not imply a trademark license. |
---|
27 | * Therefore any rights, title and interest in our trademarks remain entirely with us. |
---|
28 | * |
---|
29 | * However, if you propagate an unmodified version of the Program you are |
---|
30 | * allowed to use the term "Z-Push" to indicate that you distribute the Program. |
---|
31 | * Furthermore you may use our trademarks where it is necessary to indicate |
---|
32 | * the intended purpose of a product or service provided you use it in accordance |
---|
33 | * with honest practices in industrial or commercial matters. |
---|
34 | * If you want to propagate modified versions of the Program under the name "Z-Push", |
---|
35 | * you may only do so if you have a written permission by Zarafa Deutschland GmbH |
---|
36 | * (to acquire a permission please contact Zarafa at trademark@zarafa.com). |
---|
37 | * |
---|
38 | * This program is distributed in the hope that it will be useful, |
---|
39 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
40 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
41 | * GNU Affero General Public License for more details. |
---|
42 | * |
---|
43 | * You should have received a copy of the GNU Affero General Public License |
---|
44 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
---|
45 | * |
---|
46 | * Consult LICENSE file for details |
---|
47 | ************************************************/ |
---|
48 | |
---|
49 | |
---|
50 | abstract class SyncObject extends Streamer { |
---|
51 | const STREAMER_CHECKS = 6; |
---|
52 | const STREAMER_CHECK_REQUIRED = 7; |
---|
53 | const STREAMER_CHECK_ZEROORONE = 8; |
---|
54 | const STREAMER_CHECK_NOTALLOWED = 9; |
---|
55 | const STREAMER_CHECK_ONEVALUEOF = 10; |
---|
56 | const STREAMER_CHECK_SETZERO = "setToValue0"; |
---|
57 | const STREAMER_CHECK_SETONE = "setToValue1"; |
---|
58 | const STREAMER_CHECK_SETTWO = "setToValue2"; |
---|
59 | const STREAMER_CHECK_SETEMPTY = "setToValueEmpty"; |
---|
60 | const STREAMER_CHECK_CMPLOWER = 13; |
---|
61 | const STREAMER_CHECK_CMPHIGHER = 14; |
---|
62 | const STREAMER_CHECK_LENGTHMAX = 15; |
---|
63 | const STREAMER_CHECK_EMAIL = 16; |
---|
64 | |
---|
65 | protected $unsetVars; |
---|
66 | |
---|
67 | |
---|
68 | public function SyncObject($mapping) { |
---|
69 | $this->unsetVars = array(); |
---|
70 | parent::Streamer($mapping); |
---|
71 | } |
---|
72 | |
---|
73 | /** |
---|
74 | * Sets all supported but not transmitted variables |
---|
75 | * of this SyncObject to an "empty" value, so they are deleted when being saved |
---|
76 | * |
---|
77 | * @param array $supportedFields array with all supported fields, if available |
---|
78 | * |
---|
79 | * @access public |
---|
80 | * @return boolean |
---|
81 | */ |
---|
82 | public function emptySupported($supportedFields) { |
---|
83 | if ($supportedFields === false || !is_array($supportedFields)) |
---|
84 | return false; |
---|
85 | |
---|
86 | foreach ($supportedFields as $field) { |
---|
87 | if (!isset($this->mapping[$field])) { |
---|
88 | ZLog::Write(LOGLEVEL_WARN, sprintf("Field '%s' is supposed to be emptied but is not defined for '%s'", $field, get_class($this))); |
---|
89 | continue; |
---|
90 | } |
---|
91 | $var = $this->mapping[$field][self::STREAMER_VAR]; |
---|
92 | // add var to $this->unsetVars if $var is not set |
---|
93 | if (!isset($this->$var)) |
---|
94 | $this->unsetVars[] = $var; |
---|
95 | } |
---|
96 | ZLog::Write(LOGLEVEL_DEBUG, sprintf("Supported variables to be unset: %s", implode(',', $this->unsetVars))); |
---|
97 | return true; |
---|
98 | } |
---|
99 | |
---|
100 | |
---|
101 | /** |
---|
102 | * Compares this a SyncObject to another. |
---|
103 | * In case that all available mapped fields are exactly EQUAL, it returns true |
---|
104 | * |
---|
105 | * @see SyncObject |
---|
106 | * @param SyncObject $odo other SyncObject |
---|
107 | * @return boolean |
---|
108 | */ |
---|
109 | public function equals($odo, $log = false) { |
---|
110 | if ($odo === false) |
---|
111 | return false; |
---|
112 | |
---|
113 | // check objecttype |
---|
114 | if (! ($odo instanceof SyncObject)) { |
---|
115 | ZLog::Write(LOGLEVEL_DEBUG, "SyncObject->equals() the target object is not a SyncObject"); |
---|
116 | return false; |
---|
117 | } |
---|
118 | |
---|
119 | // check for mapped fields |
---|
120 | foreach ($this->mapping as $v) { |
---|
121 | $val = $v[self::STREAMER_VAR]; |
---|
122 | // array of values? |
---|
123 | if (isset($v[self::STREAMER_ARRAY])) { |
---|
124 | // seek for differences in the arrays |
---|
125 | if (is_array($this->$val) && is_array($odo->$val)) { |
---|
126 | if (count(array_diff($this->$val, $odo->$val)) + count(array_diff($odo->$val, $this->$val)) > 0) { |
---|
127 | ZLog::Write(LOGLEVEL_DEBUG, sprintf("SyncObject->equals() items in array '%s' differ", $val)); |
---|
128 | return false; |
---|
129 | } |
---|
130 | } |
---|
131 | else { |
---|
132 | ZLog::Write(LOGLEVEL_DEBUG, sprintf("SyncObject->equals() array '%s' is set in one but not the other object", $val)); |
---|
133 | return false; |
---|
134 | } |
---|
135 | } |
---|
136 | else { |
---|
137 | if (isset($this->$val) && isset($odo->$val)) { |
---|
138 | if ($this->$val != $odo->$val){ |
---|
139 | ZLog::Write(LOGLEVEL_DEBUG, sprintf("SyncObject->equals() false on field '%s': '%s' != '%s'", $val, Utils::PrintAsString($this->$val), Utils::PrintAsString($odo->$val))); |
---|
140 | return false; |
---|
141 | } |
---|
142 | } |
---|
143 | else if (!isset($this->$val) && !isset($odo->$val)) { |
---|
144 | continue; |
---|
145 | } |
---|
146 | else { |
---|
147 | ZLog::Write(LOGLEVEL_DEBUG, sprintf("SyncObject->equals() false because field '%s' is only defined at one obj: '%s' != '%s'", $val, Utils::PrintAsString(isset($this->$val)), Utils::PrintAsString(isset($odo->$val)))); |
---|
148 | return false; |
---|
149 | } |
---|
150 | } |
---|
151 | } |
---|
152 | |
---|
153 | return true; |
---|
154 | } |
---|
155 | |
---|
156 | /** |
---|
157 | * String representation of the object |
---|
158 | * |
---|
159 | * @return String |
---|
160 | */ |
---|
161 | public function __toString() { |
---|
162 | $str = get_class($this) . " (\n"; |
---|
163 | |
---|
164 | $streamerVars = array(); |
---|
165 | foreach ($this->mapping as $k=>$v) |
---|
166 | $streamerVars[$v[self::STREAMER_VAR]] = (isset($v[self::STREAMER_TYPE]))?$v[self::STREAMER_TYPE]:false; |
---|
167 | |
---|
168 | foreach (get_object_vars($this) as $k=>$v) { |
---|
169 | if ($k == "mapping") continue; |
---|
170 | |
---|
171 | if (array_key_exists($k, $streamerVars)) |
---|
172 | $strV = "(S) "; |
---|
173 | else |
---|
174 | $strV = ""; |
---|
175 | |
---|
176 | // self::STREAMER_ARRAY ? |
---|
177 | if (is_array($v)) { |
---|
178 | $str .= "\t". $strV . $k ."(Array) size: " . count($v) ."\n"; |
---|
179 | foreach ($v as $value) $str .= "\t\t". Utils::PrintAsString($value) ."\n"; |
---|
180 | } |
---|
181 | else if ($v instanceof SyncObject) { |
---|
182 | $str .= "\t". $strV .$k ." => ". str_replace("\n", "\n\t\t\t", $v->__toString()) . "\n"; |
---|
183 | } |
---|
184 | else |
---|
185 | $str .= "\t". $strV .$k ." => " . (isset($this->$k)? Utils::PrintAsString($this->$k) :"null") . "\n"; |
---|
186 | } |
---|
187 | $str .= ")"; |
---|
188 | |
---|
189 | return $str; |
---|
190 | } |
---|
191 | |
---|
192 | /** |
---|
193 | * Returns the properties which have to be unset on the server |
---|
194 | * |
---|
195 | * @access public |
---|
196 | * @return array |
---|
197 | */ |
---|
198 | public function getUnsetVars() { |
---|
199 | return $this->unsetVars; |
---|
200 | } |
---|
201 | |
---|
202 | /** |
---|
203 | * Method checks if the object has the minimum of required parameters |
---|
204 | * and fullfills semantic dependencies |
---|
205 | * |
---|
206 | * General checks: |
---|
207 | * STREAMER_CHECK_REQUIRED may have as value false (do not fix, ignore object!) or set-to-values: STREAMER_CHECK_SETZERO/ONE/TWO, STREAMER_CHECK_SETEMPTY |
---|
208 | * STREAMER_CHECK_ZEROORONE may be 0 or 1, if none of these, set-to-values: STREAMER_CHECK_SETZERO or STREAMER_CHECK_SETONE |
---|
209 | * STREAMER_CHECK_NOTALLOWED fails if is set |
---|
210 | * STREAMER_CHECK_ONEVALUEOF expects an array with accepted values, fails if value is not in array |
---|
211 | * |
---|
212 | * Comparison: |
---|
213 | * STREAMER_CHECK_CMPLOWER compares if the current parameter is lower as a literal or another parameter of the same object |
---|
214 | * STREAMER_CHECK_CMPHIGHER compares if the current parameter is higher as a literal or another parameter of the same object |
---|
215 | * |
---|
216 | * @param boolean $logAsDebug (opt) default is false, so messages are logged in WARN log level |
---|
217 | * |
---|
218 | * @access public |
---|
219 | * @return boolean |
---|
220 | */ |
---|
221 | public function Check($logAsDebug = false) { |
---|
222 | // semantic checks general "turn off switch" |
---|
223 | if (defined("DO_SEMANTIC_CHECKS") && DO_SEMANTIC_CHECKS === false) { |
---|
224 | ZLog::Write(LOGLEVEL_DEBUG, "SyncObject->Check(): semantic checks disabled. Check your config for 'DO_SEMANTIC_CHECKS'."); |
---|
225 | return true; |
---|
226 | } |
---|
227 | |
---|
228 | $defaultLogLevel = LOGLEVEL_WARN; |
---|
229 | |
---|
230 | // in some cases non-false checks should not provoke a WARN log but only a DEBUG log |
---|
231 | if ($logAsDebug) |
---|
232 | $defaultLogLevel = LOGLEVEL_DEBUG; |
---|
233 | |
---|
234 | $objClass = get_class($this); |
---|
235 | foreach ($this->mapping as $k=>$v) { |
---|
236 | |
---|
237 | // check sub-objects recursively |
---|
238 | if (isset($v[self::STREAMER_TYPE]) && isset($this->$v[self::STREAMER_VAR])) { |
---|
239 | if ($this->$v[self::STREAMER_VAR] instanceof SyncObject) { |
---|
240 | if (! $this->$v[self::STREAMER_VAR]->Check($logAsDebug)) |
---|
241 | return false; |
---|
242 | } |
---|
243 | else if (is_array($this->$v[self::STREAMER_VAR])) { |
---|
244 | foreach ($this->$v[self::STREAMER_VAR] as $subobj) |
---|
245 | if ($subobj instanceof SyncObject && !$subobj->Check($logAsDebug)) |
---|
246 | return false; |
---|
247 | } |
---|
248 | } |
---|
249 | |
---|
250 | if (isset($v[self::STREAMER_CHECKS])) { |
---|
251 | foreach ($v[self::STREAMER_CHECKS] as $rule => $condition) { |
---|
252 | // check REQUIRED settings |
---|
253 | if ($rule === self::STREAMER_CHECK_REQUIRED && (!isset($this->$v[self::STREAMER_VAR]) || $this->$v[self::STREAMER_VAR] === '' ) ) { |
---|
254 | // parameter is not set but .. |
---|
255 | // requested to set to 0 |
---|
256 | if ($condition === self::STREAMER_CHECK_SETZERO) { |
---|
257 | $this->$v[self::STREAMER_VAR] = 0; |
---|
258 | ZLog::Write($defaultLogLevel, sprintf("SyncObject->Check(): Fixed object from type %s: parameter '%s' is set to 0", $objClass, $v[self::STREAMER_VAR])); |
---|
259 | } |
---|
260 | // requested to be set to 1 |
---|
261 | else if ($condition === self::STREAMER_CHECK_SETONE) { |
---|
262 | $this->$v[self::STREAMER_VAR] = 1; |
---|
263 | ZLog::Write($defaultLogLevel, sprintf("SyncObject->Check(): Fixed object from type %s: parameter '%s' is set to 1", $objClass, $v[self::STREAMER_VAR])); |
---|
264 | } |
---|
265 | // requested to be set to 2 |
---|
266 | else if ($condition === self::STREAMER_CHECK_SETTWO) { |
---|
267 | $this->$v[self::STREAMER_VAR] = 2; |
---|
268 | ZLog::Write($defaultLogLevel, sprintf("SyncObject->Check(): Fixed object from type %s: parameter '%s' is set to 2", $objClass, $v[self::STREAMER_VAR])); |
---|
269 | } |
---|
270 | // requested to be set to '' |
---|
271 | else if ($condition === self::STREAMER_CHECK_SETEMPTY) { |
---|
272 | if (!isset($this->$v[self::STREAMER_VAR])) { |
---|
273 | $this->$v[self::STREAMER_VAR] = ''; |
---|
274 | ZLog::Write($defaultLogLevel, sprintf("SyncObject->Check(): Fixed object from type %s: parameter '%s' is set to ''", $objClass, $v[self::STREAMER_VAR])); |
---|
275 | } |
---|
276 | } |
---|
277 | // there is another value !== false |
---|
278 | else if ($condition !== false) { |
---|
279 | $this->$v[self::STREAMER_VAR] = $condition; |
---|
280 | ZLog::Write($defaultLogLevel, sprintf("SyncObject->Check(): Fixed object from type %s: parameter '%s' is set to '%s'", $objClass, $v[self::STREAMER_VAR], $condition)); |
---|
281 | |
---|
282 | } |
---|
283 | // no fix available! |
---|
284 | else { |
---|
285 | ZLog::Write($defaultLogLevel, sprintf("SyncObject->Check(): Unmet condition in object from type %s: parameter '%s' is required but not set. Check failed!", $objClass, $v[self::STREAMER_VAR])); |
---|
286 | return false; |
---|
287 | } |
---|
288 | } // end STREAMER_CHECK_REQUIRED |
---|
289 | |
---|
290 | |
---|
291 | // check STREAMER_CHECK_ZEROORONE |
---|
292 | if ($rule === self::STREAMER_CHECK_ZEROORONE && isset($this->$v[self::STREAMER_VAR])) { |
---|
293 | if ($this->$v[self::STREAMER_VAR] != 0 && $this->$v[self::STREAMER_VAR] != 1) { |
---|
294 | $newval = $condition === self::STREAMER_CHECK_SETZERO ? 0:1; |
---|
295 | $this->$v[self::STREAMER_VAR] = $newval; |
---|
296 | ZLog::Write($defaultLogLevel, sprintf("SyncObject->Check(): Fixed object from type %s: parameter '%s' is set to '%s' as it was not 0 or 1", $objClass, $v[self::STREAMER_VAR], $newval)); |
---|
297 | } |
---|
298 | }// end STREAMER_CHECK_ZEROORONE |
---|
299 | |
---|
300 | |
---|
301 | // check STREAMER_CHECK_ONEVALUEOF |
---|
302 | if ($rule === self::STREAMER_CHECK_ONEVALUEOF && isset($this->$v[self::STREAMER_VAR])) { |
---|
303 | if (!in_array($this->$v[self::STREAMER_VAR], $condition)) { |
---|
304 | ZLog::Write($defaultLogLevel, sprintf("SyncObject->Check(): object from type %s: parameter '%s'->'%s' is not in the range of allowed values.", $objClass, $v[self::STREAMER_VAR], $this->$v[self::STREAMER_VAR])); |
---|
305 | return false; |
---|
306 | } |
---|
307 | }// end STREAMER_CHECK_ONEVALUEOF |
---|
308 | |
---|
309 | |
---|
310 | // Check value compared to other value or literal |
---|
311 | if ($rule === self::STREAMER_CHECK_CMPHIGHER || $rule === self::STREAMER_CHECK_CMPLOWER) { |
---|
312 | if (isset($this->$v[self::STREAMER_VAR])) { |
---|
313 | $cmp = false; |
---|
314 | // directly compare against literals |
---|
315 | if (is_int($condition)) { |
---|
316 | $cmp = $condition; |
---|
317 | } |
---|
318 | // check for invalid compare-to |
---|
319 | else if (!isset($this->mapping[$condition])) { |
---|
320 | ZLog::Write(LOGLEVEL_ERROR, sprintf("SyncObject->Check(): Can not compare parameter '%s' against the other value '%s' as it is not defined object from type %s. Please report this! Check skipped!", $objClass, $v[self::STREAMER_VAR], $condition)); |
---|
321 | continue; |
---|
322 | } |
---|
323 | else { |
---|
324 | $cmpPar = $this->mapping[$condition][self::STREAMER_VAR]; |
---|
325 | if (isset($this->$cmpPar)) |
---|
326 | $cmp = $this->$cmpPar; |
---|
327 | } |
---|
328 | |
---|
329 | if ($cmp === false) { |
---|
330 | ZLog::Write(LOGLEVEL_WARN, sprintf("SyncObject->Check(): Unmet condition in object from type %s: parameter '%s' can not be compared, as the comparable is not set. Check failed!", $objClass, $v[self::STREAMER_VAR])); |
---|
331 | return false; |
---|
332 | } |
---|
333 | if ( ($rule == self::STREAMER_CHECK_CMPHIGHER && $this->$v[self::STREAMER_VAR] < $cmp) || |
---|
334 | ($rule == self::STREAMER_CHECK_CMPLOWER && $this->$v[self::STREAMER_VAR] > $cmp) |
---|
335 | ) { |
---|
336 | |
---|
337 | ZLog::Write(LOGLEVEL_WARN, sprintf("SyncObject->Check(): Unmet condition in object from type %s: parameter '%s' is %s than '%s'. Check failed!", |
---|
338 | $objClass, |
---|
339 | $v[self::STREAMER_VAR], |
---|
340 | (($rule === self::STREAMER_CHECK_CMPHIGHER)?'LOWER':'HIGHER'), |
---|
341 | ((isset($cmpPar)?$cmpPar:$condition)) )); |
---|
342 | return false; |
---|
343 | } |
---|
344 | } |
---|
345 | } // STREAMER_CHECK_CMP* |
---|
346 | |
---|
347 | |
---|
348 | // check STREAMER_CHECK_LENGTHMAX |
---|
349 | if ($rule === self::STREAMER_CHECK_LENGTHMAX && isset($this->$v[self::STREAMER_VAR])) { |
---|
350 | |
---|
351 | if (is_array($this->$v[self::STREAMER_VAR])) { |
---|
352 | // implosion takes 2bytes, so we just assume ", " here |
---|
353 | $chkstr = implode(", ", $this->$v[self::STREAMER_VAR]); |
---|
354 | } |
---|
355 | else |
---|
356 | $chkstr = $this->$v[self::STREAMER_VAR]; |
---|
357 | |
---|
358 | if (strlen($chkstr) > $condition) { |
---|
359 | ZLog::Write(LOGLEVEL_WARN, sprintf("SyncObject->Check(): object from type %s: parameter '%s' is longer than %d. Check failed", $objClass, $v[self::STREAMER_VAR], $condition)); |
---|
360 | return false; |
---|
361 | } |
---|
362 | }// end STREAMER_CHECK_LENGTHMAX |
---|
363 | |
---|
364 | |
---|
365 | // check STREAMER_CHECK_EMAIL |
---|
366 | // if $condition is false then the check really fails. Otherwise invalid emails are removed. |
---|
367 | // if nothing is left (all emails were false), the parameter is set to condition |
---|
368 | if ($rule === self::STREAMER_CHECK_EMAIL && isset($this->$v[self::STREAMER_VAR])) { |
---|
369 | if ($condition === false && ( (is_array($this->$v[self::STREAMER_VAR]) && empty($this->$v[self::STREAMER_VAR])) || strlen($this->$v[self::STREAMER_VAR]) == 0) ) |
---|
370 | continue; |
---|
371 | |
---|
372 | $as_array = false; |
---|
373 | |
---|
374 | if (is_array($this->$v[self::STREAMER_VAR])) { |
---|
375 | $mails = $this->$v[self::STREAMER_VAR]; |
---|
376 | $as_array = true; |
---|
377 | } |
---|
378 | else { |
---|
379 | $mails = array( $this->$v[self::STREAMER_VAR] ); |
---|
380 | } |
---|
381 | |
---|
382 | $output = array(); |
---|
383 | foreach ($mails as $mail) { |
---|
384 | if (! Utils::CheckEmail($mail)) { |
---|
385 | ZLog::Write(LOGLEVEL_WARN, sprintf("SyncObject->Check(): object from type %s: parameter '%s' contains an invalid email address '%s'. Address is removed.", $objClass, $v[self::STREAMER_VAR], $mail)); |
---|
386 | } |
---|
387 | else |
---|
388 | $output[] = $mail; |
---|
389 | } |
---|
390 | if (count($mails) != count($output)) { |
---|
391 | if ($condition === false) |
---|
392 | return false; |
---|
393 | |
---|
394 | // nothing left, use $condition as new value |
---|
395 | if (count($output) == 0) |
---|
396 | $output[] = $condition; |
---|
397 | |
---|
398 | // if we are allowed to rewrite the attribute, we do that |
---|
399 | if ($as_array) |
---|
400 | $this->$v[self::STREAMER_VAR] = $output; |
---|
401 | else |
---|
402 | $this->$v[self::STREAMER_VAR] = $output[0]; |
---|
403 | } |
---|
404 | }// end STREAMER_CHECK_EMAIL |
---|
405 | |
---|
406 | |
---|
407 | } // foreach CHECKS |
---|
408 | } // isset CHECKS |
---|
409 | } // foreach mapping |
---|
410 | |
---|
411 | return true; |
---|
412 | } |
---|
413 | } |
---|
414 | |
---|
415 | ?> |
---|