1 /**********************************************************************
2  * $Id: php_mapscript.c 9765 2010-01-28 15:32:10Z aboudreault $
3  *
4  * Project:  MapServer
5  * Purpose:  PHP/MapScript extension for MapServer.  External interface
6  *           functions
7  * Author:   Daniel Morissette, DM Solutions Group (dmorissette@dmsolutions.ca)
8  *           Alan Boudreault, Mapgears
9  *
10  **********************************************************************
11  * Copyright (c) 2000-2010, Daniel Morissette, DM Solutions Group Inc.
12  *
13  * Permission is hereby granted, free of charge, to any person obtaining a
14  * copy of this software and associated documentation files (the "Software"),
15  * to deal in the Software without restriction, including without limitation
16  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17  * and/or sell copies of the Software, and to permit persons to whom the
18  * Software is furnished to do so, subject to the following conditions:
19  *
20  * The above copyright notice and this permission notice shall be included in
21  * all copies of this Software or works derived from this Software.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
26  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29  * DEALINGS IN THE SOFTWARE.
30  **********************************************************************/
31 
32 #include "php_mapscript.h"
33 
34 #if PHP_VERSION_ID >= 50625 && PHP_VERSION_ID < 70000
35 #undef ZVAL_STRING
36 #define ZVAL_STRING(z, s, duplicate) do {       \
37     const char *__s=(s);                            \
38     zval *__z = (z);                                        \
39     Z_STRLEN_P(__z) = strlen(__s);          \
40     Z_STRVAL_P(__z) = (duplicate?estrndup(__s, Z_STRLEN_P(__z)):(char*)__s);\
41     Z_TYPE_P(__z) = IS_STRING;                      \
42 } while (0)
43 #endif
44 
45 #undef ZVAL_STRING
46 #define ZVAL_STRING(z, s, duplicate) do {       \
47                 const char *__s=(s);                            \
48                 zval *__z = (z);                                        \
49                 Z_STRLEN_P(__z) = strlen(__s);          \
50                 Z_STRVAL_P(__z) = (duplicate?estrndup(__s, Z_STRLEN_P(__z)):(char*)__s);\
51                 Z_TYPE_P(__z) = IS_STRING;                      \
52         } while (0)
53 
54 zend_class_entry *mapscript_ce_error;
55 #if PHP_VERSION_ID >= 70000
56 zend_object_handlers mapscript_error_object_handlers;
57 #endif
58 
59 ZEND_BEGIN_ARG_INFO_EX(error___get_args, 0, 0, 1)
60 ZEND_ARG_INFO(0, property)
ZEND_END_ARG_INFO()61 ZEND_END_ARG_INFO()
62 
63 ZEND_BEGIN_ARG_INFO_EX(error___set_args, 0, 0, 2)
64 ZEND_ARG_INFO(0, property)
65 ZEND_ARG_INFO(0, value)
66 ZEND_END_ARG_INFO()
67 
68 /* {{{ proto error __construct()
69    errorObj CANNOT be instanciated, this will throw an exception on use */
70 PHP_METHOD(errorObj, __construct)
71 {
72   mapscript_throw_exception("errorObj cannot be constructed" TSRMLS_CC);
73 }
74 /* }}} */
75 
PHP_METHOD(errorObj,__get)76 PHP_METHOD(errorObj, __get)
77 {
78   char *property;
79   long property_len = 0;
80   zval *zobj = getThis();
81   /* php_error is in PHP7 defined in php.h, so we use php_errobj instead */
82   php_error_object *php_errobj;
83 
84   PHP_MAPSCRIPT_ERROR_HANDLING(TRUE);
85   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",
86                             &property, &property_len) == FAILURE) {
87     PHP_MAPSCRIPT_RESTORE_ERRORS(TRUE);
88     return;
89   }
90   PHP_MAPSCRIPT_RESTORE_ERRORS(TRUE);
91 
92   php_errobj = MAPSCRIPT_OBJ_P(php_error_object, zobj);
93 
94   IF_GET_LONG("code", php_errobj->error->code)
95   else IF_GET_STRING("routine", php_errobj->error->routine)
96     else IF_GET_STRING("message", php_errobj->error->message)
97       else IF_GET_LONG("isreported", php_errobj->error->isreported)
98         else {
99           mapscript_throw_exception("Property '%s' does not exist in this object." TSRMLS_CC, property);
100         }
101 }
102 
PHP_METHOD(errorObj,__set)103 PHP_METHOD(errorObj, __set)
104 {
105   char *property;
106   long property_len = 0;
107   zval *value;
108   /* zval *zobj = getThis(); */
109   /* php_error_object *php_errobj; */
110 
111   PHP_MAPSCRIPT_ERROR_HANDLING(TRUE);
112   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz",
113                             &property, &property_len, &value) == FAILURE) {
114     PHP_MAPSCRIPT_RESTORE_ERRORS(TRUE);
115     return;
116   }
117   PHP_MAPSCRIPT_RESTORE_ERRORS(TRUE);
118 
119   /* php_errobj = MAPSCRIPT_OBJ_P(php_error_object, zobj); */
120 
121   if ( (STRING_EQUAL("code", property)) ||
122        (STRING_EQUAL("routine", property)) ||
123        (STRING_EQUAL("isreported", property)) ||
124        (STRING_EQUAL("message", property))) {
125     mapscript_throw_exception("Property '%s' is read-only and cannot be set." TSRMLS_CC, property);
126   } else {
127     mapscript_throw_exception("Property '%s' does not exist in this object." TSRMLS_CC, property);
128   }
129 }
130 
131 /* {{{ proto int error.next()
132    Returns a ref to the next errorObj in the list, or NULL if we reached the last one */
PHP_METHOD(errorObj,next)133 PHP_METHOD(errorObj, next)
134 {
135   zval *zobj = getThis();
136   php_error_object *php_errobj;
137   errorObj *error = NULL;
138 
139   PHP_MAPSCRIPT_ERROR_HANDLING(TRUE);
140   if (zend_parse_parameters_none() == FAILURE) {
141     PHP_MAPSCRIPT_RESTORE_ERRORS(TRUE);
142     return;
143   }
144   PHP_MAPSCRIPT_RESTORE_ERRORS(TRUE);
145 
146   php_errobj = MAPSCRIPT_OBJ_P(php_error_object, zobj);
147 
148   if (php_errobj->error->next == NULL)
149     RETURN_NULL();
150 
151   /* Make sure 'self' is still valid.  It may have been deleted by
152    * msResetErrorList() */
153   error = msGetErrorObj();
154   while(error != php_errobj->error) {
155     if (error->next == NULL) {
156       mapscript_throw_exception("Trying to access an errorObj that has expired." TSRMLS_CC);
157       return;
158     }
159     error = error->next;
160   }
161 
162   php_errobj->error = php_errobj->error->next;
163   *return_value = *zobj;
164   zval_copy_ctor(return_value);
165   INIT_PZVAL(return_value);
166 }
167 /* }}} */
168 
169 zend_function_entry error_functions[] = {
170   PHP_ME(errorObj, __construct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
171   PHP_ME(errorObj, __get, error___get_args, ZEND_ACC_PUBLIC)
172   PHP_ME(errorObj, __set, error___set_args, ZEND_ACC_PUBLIC)
173   PHP_ME(errorObj, next, NULL, ZEND_ACC_PUBLIC) {
174     NULL, NULL, NULL
175   }
176 };
177 
mapscript_create_error(errorObj * error,zval * return_value TSRMLS_DC)178 void mapscript_create_error(errorObj *error, zval *return_value TSRMLS_DC)
179 {
180   php_error_object * php_errobj;
181   object_init_ex(return_value, mapscript_ce_error);
182   php_errobj = MAPSCRIPT_OBJ_P(php_error_object, return_value);
183   php_errobj->error = error;
184 }
185 
186 #if PHP_VERSION_ID >= 70000
187 /* PHP7 - Modification by Bjoern Boldt <mapscript@pixaweb.net> */
mapscript_error_create_object(zend_class_entry * ce TSRMLS_DC)188 static zend_object *mapscript_error_create_object(zend_class_entry *ce TSRMLS_DC)
189 {
190   php_error_object *php_errobj;
191 
192   php_errobj = ecalloc(1, sizeof(*php_errobj) + zend_object_properties_size(ce));
193 
194   zend_object_std_init(&php_errobj->zobj, ce TSRMLS_CC);
195   object_properties_init(&php_errobj->zobj, ce);
196 
197   php_errobj->zobj.handlers = &mapscript_error_object_handlers;
198 
199   return &php_errobj->zobj;
200 }
201 
202 /*
203 static void mapscript_error_free_object(zend_object *object)
204 {
205   php_error_object *php_errobj;
206 
207   php_errobj = (php_error_object *)((char *)object - XtOffsetOf(php_error_object, zobj));
208 
209   zend_object_std_dtor(object);
210 }
211 */
212 
PHP_MINIT_FUNCTION(error)213 PHP_MINIT_FUNCTION(error)
214 {
215   zend_class_entry ce;
216 
217   INIT_CLASS_ENTRY(ce, "errorObj", error_functions);
218   mapscript_ce_error = zend_register_internal_class(&ce TSRMLS_CC);
219 
220   mapscript_ce_error->create_object = mapscript_error_create_object;
221   mapscript_ce_error->ce_flags |= ZEND_ACC_FINAL;
222 
223   memcpy(&mapscript_error_object_handlers, &mapscript_std_object_handlers, sizeof(mapscript_error_object_handlers));
224   /* mapscript_error_object_handlers.free_obj = mapscript_error_free_object; // nothing to do here -> use standard handler */
225   mapscript_error_object_handlers.offset   = XtOffsetOf(php_error_object, zobj);
226 
227   return SUCCESS;
228 }
229 #else
230 /* PHP5 */
mapscript_error_object_destroy(void * object TSRMLS_DC)231 static void mapscript_error_object_destroy(void *object TSRMLS_DC)
232 {
233   php_error_object *php_errobj = (php_error_object *)object;
234 
235   MAPSCRIPT_FREE_OBJECT(php_errobj);
236 
237   /* We don't need to free the errorObj */
238 
239   efree(object);
240 }
241 
mapscript_error_object_new(zend_class_entry * ce TSRMLS_DC)242 static zend_object_value mapscript_error_object_new(zend_class_entry *ce TSRMLS_DC)
243 {
244   zend_object_value retval;
245   php_error_object *php_errobj;
246 
247   MAPSCRIPT_ALLOC_OBJECT(php_errobj, php_error_object);
248 
249   retval = mapscript_object_new(&php_errobj->std, ce,
250                                 &mapscript_error_object_destroy TSRMLS_CC);
251 
252   return retval;
253 }
254 
PHP_MINIT_FUNCTION(error)255 PHP_MINIT_FUNCTION(error)
256 {
257   zend_class_entry ce;
258 
259   MAPSCRIPT_REGISTER_CLASS("errorObj",
260                            error_functions,
261                            mapscript_ce_error,
262                            mapscript_error_object_new);
263 
264   mapscript_ce_error->ce_flags |= ZEND_ACC_FINAL_CLASS;
265 
266   return SUCCESS;
267 }
268 #endif
269