1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2018 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Authors: Ard Biesheuvel <a.k.biesheuvel@its.tudelft.nl> |
16 +----------------------------------------------------------------------+
17 */
18
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22
23 #include "php.h"
24
25 #if HAVE_IBASE
26
27 #include "php_interbase.h"
28 #include "php_ibase_includes.h"
29
30 #define BLOB_CLOSE 1
31 #define BLOB_CANCEL 2
32
33 #define PARSE_PARAMETERS \
34 switch (ZEND_NUM_ARGS()) { \
35 default: \
36 WRONG_PARAM_COUNT; \
37 case 1: \
38 if (FAILURE == zend_parse_parameters(1, "s", &blob_id, &blob_id_len)) { \
39 RETURN_FALSE; \
40 } \
41 break; \
42 case 2: \
43 if (FAILURE == zend_parse_parameters(2, "rs", &link, &blob_id, &blob_id_len)) { \
44 RETURN_FALSE; \
45 } \
46 break; \
47 } \
48
49 static int le_blob;
50
_php_ibase_free_blob(zend_resource * rsrc)51 static void _php_ibase_free_blob(zend_resource *rsrc) /* {{{ */
52 {
53 ibase_blob *ib_blob = (ibase_blob *)rsrc->ptr;
54
55 if (ib_blob->bl_handle != 0) { /* blob open*/
56 if (isc_cancel_blob(IB_STATUS, &ib_blob->bl_handle)) {
57 _php_ibase_module_error("You can lose data. Close any blob after reading from or "
58 "writing to it. Use ibase_blob_close() before calling ibase_close()");
59 }
60 }
61 efree(ib_blob);
62 }
63 /* }}} */
64
php_ibase_blobs_minit(INIT_FUNC_ARGS)65 void php_ibase_blobs_minit(INIT_FUNC_ARGS) /* {{{ */
66 {
67 le_blob = zend_register_list_destructors_ex(_php_ibase_free_blob, NULL,
68 "interbase blob", module_number);
69 }
70 /* }}} */
71
_php_ibase_string_to_quad(char const * id,ISC_QUAD * qd)72 int _php_ibase_string_to_quad(char const *id, ISC_QUAD *qd) /* {{{ */
73 {
74 /* shortcut for most common case */
75 if (sizeof(ISC_QUAD) == sizeof(ISC_UINT64)) {
76 return sscanf(id, BLOB_ID_MASK, (ISC_UINT64 *) qd);
77 } else {
78 ISC_UINT64 res;
79 if (sscanf(id, BLOB_ID_MASK, &res)) {
80 qd->gds_quad_high = (ISC_LONG) (res >> 0x20);
81 qd->gds_quad_low = (ISC_LONG) (res & 0xFFFFFFFF);
82 return 1;
83 }
84 return 0;
85 }
86 }
87 /* }}} */
88
_php_ibase_quad_to_string(ISC_QUAD const qd)89 zend_string *_php_ibase_quad_to_string(ISC_QUAD const qd) /* {{{ */
90 {
91 /* shortcut for most common case */
92 if (sizeof(ISC_QUAD) == sizeof(ISC_UINT64)) {
93 return strpprintf(BLOB_ID_LEN+1, "0x%0*" LL_MASK "x", 16, *(ISC_UINT64*)(void *) &qd);
94 } else {
95 ISC_UINT64 res = ((ISC_UINT64) qd.gds_quad_high << 0x20) | qd.gds_quad_low;
96 return strpprintf(BLOB_ID_LEN+1, "0x%0*" LL_MASK "x", 16, res);
97 }
98 }
99 /* }}} */
100
101 typedef struct { /* {{{ */
102 ISC_LONG max_segment; /* Length of longest segment */
103 ISC_LONG num_segments; /* Total number of segments */
104 ISC_LONG total_length; /* Total length of blob */
105 int bl_stream; /* blob is stream ? */
106 /* }}} */
107 } IBASE_BLOBINFO;
108
_php_ibase_blob_get(zval * return_value,ibase_blob * ib_blob,zend_ulong max_len)109 int _php_ibase_blob_get(zval *return_value, ibase_blob *ib_blob, zend_ulong max_len) /* {{{ */
110 {
111 if (ib_blob->bl_qd.gds_quad_high || ib_blob->bl_qd.gds_quad_low) { /*not null ?*/
112
113 ISC_STATUS stat;
114 zend_string *bl_data;
115 zend_ulong cur_len;
116 unsigned short seg_len;
117
118 bl_data = zend_string_safe_alloc(1, max_len, 0, 0);
119
120 for (cur_len = stat = 0; (stat == 0 || stat == isc_segment) && cur_len < max_len; cur_len += seg_len) {
121
122 unsigned short chunk_size = (max_len-cur_len) > USHRT_MAX ? USHRT_MAX
123 : (unsigned short)(max_len-cur_len);
124
125 stat = isc_get_segment(IB_STATUS, &ib_blob->bl_handle, &seg_len, chunk_size, &ZSTR_VAL(bl_data)[cur_len]);
126 }
127
128 if (IB_STATUS[0] == 1 && (stat != 0 && stat != isc_segstr_eof && stat != isc_segment)) {
129 zend_string_free(bl_data);
130 _php_ibase_error();
131 return FAILURE;
132 }
133 ZSTR_VAL(bl_data)[cur_len] = '\0';
134 ZSTR_LEN(bl_data) = cur_len;
135 RETVAL_NEW_STR(bl_data);
136 } else { /* null blob */
137 RETVAL_EMPTY_STRING(); /* empty string */
138 }
139 return SUCCESS;
140 }
141 /* }}} */
142
_php_ibase_blob_add(zval * string_arg,ibase_blob * ib_blob)143 int _php_ibase_blob_add(zval *string_arg, ibase_blob *ib_blob) /* {{{ */
144 {
145 zend_ulong put_cnt = 0, rem_cnt;
146 unsigned short chunk_size;
147
148 convert_to_string_ex(string_arg);
149
150 for (rem_cnt = Z_STRLEN_P(string_arg); rem_cnt > 0; rem_cnt -= chunk_size) {
151
152 chunk_size = rem_cnt > USHRT_MAX ? USHRT_MAX : (unsigned short)rem_cnt;
153
154 if (isc_put_segment(IB_STATUS, &ib_blob->bl_handle, chunk_size, &Z_STRVAL_P(string_arg)[put_cnt] )) {
155 _php_ibase_error();
156 return FAILURE;
157 }
158 put_cnt += chunk_size;
159 }
160 return SUCCESS;
161 }
162 /* }}} */
163
_php_ibase_blob_info(isc_blob_handle bl_handle,IBASE_BLOBINFO * bl_info)164 static int _php_ibase_blob_info(isc_blob_handle bl_handle, IBASE_BLOBINFO *bl_info) /* {{{ */
165 {
166 static char bl_items[] = {
167 isc_info_blob_num_segments,
168 isc_info_blob_max_segment,
169 isc_info_blob_total_length,
170 isc_info_blob_type
171 };
172
173 char bl_inf[sizeof(zend_long)*8], *p;
174
175 bl_info->max_segment = 0;
176 bl_info->num_segments = 0;
177 bl_info->total_length = 0;
178 bl_info->bl_stream = 0;
179
180 if (isc_blob_info(IB_STATUS, &bl_handle, sizeof(bl_items), bl_items, sizeof(bl_inf), bl_inf)) {
181 _php_ibase_error();
182 return FAILURE;
183 }
184
185 for (p = bl_inf; *p != isc_info_end && p < bl_inf + sizeof(bl_inf);) {
186 unsigned short item_len;
187 int item = *p++;
188
189 item_len = (short) isc_vax_integer(p, 2);
190 p += 2;
191 switch (item) {
192 case isc_info_blob_num_segments:
193 bl_info->num_segments = isc_vax_integer(p, item_len);
194 break;
195 case isc_info_blob_max_segment:
196 bl_info->max_segment = isc_vax_integer(p, item_len);
197 break;
198 case isc_info_blob_total_length:
199 bl_info->total_length = isc_vax_integer(p, item_len);
200 break;
201 case isc_info_blob_type:
202 bl_info->bl_stream = isc_vax_integer(p, item_len);
203 break;
204 case isc_info_end:
205 break;
206 case isc_info_truncated:
207 case isc_info_error: /* hmm. don't think so...*/
208 _php_ibase_module_error("PHP module internal error");
209 return FAILURE;
210 } /* switch */
211 p += item_len;
212 } /* for */
213 return SUCCESS;
214 }
215 /* }}} */
216
217 /* {{{ proto resource ibase_blob_create([resource link_identifier])
218 Create blob for adding data */
PHP_FUNCTION(ibase_blob_create)219 PHP_FUNCTION(ibase_blob_create)
220 {
221 zval *link = NULL;
222 ibase_db_link *ib_link;
223 ibase_trans *trans = NULL;
224 ibase_blob *ib_blob;
225
226 RESET_ERRMSG;
227
228 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "|r", &link)) {
229 RETURN_FALSE;
230 }
231
232 PHP_IBASE_LINK_TRANS(link, ib_link, trans);
233
234 ib_blob = (ibase_blob *) emalloc(sizeof(ibase_blob));
235 ib_blob->bl_handle = 0;
236 ib_blob->type = BLOB_INPUT;
237
238 if (isc_create_blob(IB_STATUS, &ib_link->handle, &trans->handle, &ib_blob->bl_handle, &ib_blob->bl_qd)) {
239 _php_ibase_error();
240 efree(ib_blob);
241 RETURN_FALSE;
242 }
243
244 RETVAL_RES(zend_register_resource(ib_blob, le_blob));
245 Z_TRY_ADDREF_P(return_value);
246 }
247 /* }}} */
248
249 /* {{{ proto resource ibase_blob_open([ resource link_identifier, ] string blob_id)
250 Open blob for retrieving data parts */
PHP_FUNCTION(ibase_blob_open)251 PHP_FUNCTION(ibase_blob_open)
252 {
253 char *blob_id;
254 size_t blob_id_len;
255 zval *link = NULL;
256 ibase_db_link *ib_link;
257 ibase_trans *trans = NULL;
258 ibase_blob *ib_blob;
259
260 RESET_ERRMSG;
261 PARSE_PARAMETERS;
262
263 PHP_IBASE_LINK_TRANS(link, ib_link, trans);
264
265 ib_blob = (ibase_blob *) emalloc(sizeof(ibase_blob));
266 ib_blob->bl_handle = 0;
267 ib_blob->type = BLOB_OUTPUT;
268
269 do {
270 if (! _php_ibase_string_to_quad(blob_id, &ib_blob->bl_qd)) {
271 _php_ibase_module_error("String is not a BLOB ID");
272 break;
273 }
274
275 if (isc_open_blob(IB_STATUS, &ib_link->handle, &trans->handle, &ib_blob->bl_handle,
276 &ib_blob->bl_qd)) {
277 _php_ibase_error();
278 break;
279 }
280
281 RETVAL_RES(zend_register_resource(ib_blob, le_blob));
282 Z_TRY_ADDREF_P(return_value);
283 return;
284
285 } while (0);
286
287 efree(ib_blob);
288 RETURN_FALSE;
289 }
290 /* }}} */
291
292 /* {{{ proto bool ibase_blob_add(resource blob_handle, string data)
293 Add data into created blob */
PHP_FUNCTION(ibase_blob_add)294 PHP_FUNCTION(ibase_blob_add)
295 {
296 zval *blob_arg, *string_arg;
297 ibase_blob *ib_blob;
298
299 RESET_ERRMSG;
300
301 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "rz", &blob_arg, &string_arg)) {
302 return;
303 }
304
305 ib_blob = (ibase_blob *)zend_fetch_resource_ex(blob_arg, "Interbase blob", le_blob);
306
307 if (ib_blob->type != BLOB_INPUT) {
308 _php_ibase_module_error("BLOB is not open for input");
309 RETURN_FALSE;
310 }
311
312 if (_php_ibase_blob_add(string_arg, ib_blob) != SUCCESS) {
313 RETURN_FALSE;
314 }
315 }
316 /* }}} */
317
318 /* {{{ proto string ibase_blob_get(resource blob_handle, int len)
319 Get len bytes data from open blob */
PHP_FUNCTION(ibase_blob_get)320 PHP_FUNCTION(ibase_blob_get)
321 {
322 zval *blob_arg;
323 zend_ulong len_arg;
324 ibase_blob *ib_blob;
325
326 RESET_ERRMSG;
327
328 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "rl", &blob_arg, &len_arg)) {
329 return;
330 }
331
332 ib_blob = (ibase_blob *)zend_fetch_resource_ex(blob_arg, "Interbase blob", le_blob);
333
334 if (ib_blob->type != BLOB_OUTPUT) {
335 _php_ibase_module_error("BLOB is not open for output");
336 RETURN_FALSE;
337 }
338
339 if (_php_ibase_blob_get(return_value, ib_blob, len_arg) != SUCCESS) {
340 RETURN_FALSE;
341 }
342 }
343 /* }}} */
344
_php_ibase_blob_end(INTERNAL_FUNCTION_PARAMETERS,int bl_end)345 static void _php_ibase_blob_end(INTERNAL_FUNCTION_PARAMETERS, int bl_end) /* {{{ */
346 {
347 zval *blob_arg;
348 ibase_blob *ib_blob;
349
350 RESET_ERRMSG;
351
352 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "r", &blob_arg)) {
353 return;
354 }
355
356 ib_blob = (ibase_blob *)zend_fetch_resource_ex(blob_arg, "Interbase blob", le_blob);
357
358 if (bl_end == BLOB_CLOSE) { /* return id here */
359
360 if (ib_blob->bl_qd.gds_quad_high || ib_blob->bl_qd.gds_quad_low) { /*not null ?*/
361 if (isc_close_blob(IB_STATUS, &ib_blob->bl_handle)) {
362 _php_ibase_error();
363 RETURN_FALSE;
364 }
365 }
366 ib_blob->bl_handle = 0;
367
368 RETVAL_NEW_STR(_php_ibase_quad_to_string(ib_blob->bl_qd));
369 } else { /* discard created blob */
370 if (isc_cancel_blob(IB_STATUS, &ib_blob->bl_handle)) {
371 _php_ibase_error();
372 RETURN_FALSE;
373 }
374 ib_blob->bl_handle = 0;
375 RETVAL_TRUE;
376 }
377 zend_list_delete(Z_RES_P(blob_arg));
378 }
379 /* }}} */
380
381 /* {{{ proto string ibase_blob_close(resource blob_handle)
382 Close blob */
PHP_FUNCTION(ibase_blob_close)383 PHP_FUNCTION(ibase_blob_close)
384 {
385 _php_ibase_blob_end(INTERNAL_FUNCTION_PARAM_PASSTHRU, BLOB_CLOSE);
386 }
387 /* }}} */
388
389 /* {{{ proto bool ibase_blob_cancel(resource blob_handle)
390 Cancel creating blob */
PHP_FUNCTION(ibase_blob_cancel)391 PHP_FUNCTION(ibase_blob_cancel)
392 {
393 _php_ibase_blob_end(INTERNAL_FUNCTION_PARAM_PASSTHRU, BLOB_CANCEL);
394 }
395 /* }}} */
396
397 /* {{{ proto array ibase_blob_info([ resource link_identifier, ] string blob_id)
398 Return blob length and other useful info */
PHP_FUNCTION(ibase_blob_info)399 PHP_FUNCTION(ibase_blob_info)
400 {
401 char *blob_id;
402 size_t blob_id_len;
403 zval *link = NULL;
404 ibase_db_link *ib_link;
405 ibase_trans *trans = NULL;
406 ibase_blob ib_blob = { 0, BLOB_INPUT };
407 IBASE_BLOBINFO bl_info;
408
409 RESET_ERRMSG;
410 PARSE_PARAMETERS;
411
412 PHP_IBASE_LINK_TRANS(link, ib_link, trans);
413
414 if (! _php_ibase_string_to_quad(blob_id, &ib_blob.bl_qd)) {
415 _php_ibase_module_error("Unrecognized BLOB ID");
416 RETURN_FALSE;
417 }
418
419 if (ib_blob.bl_qd.gds_quad_high || ib_blob.bl_qd.gds_quad_low) { /* not null ? */
420 if (isc_open_blob(IB_STATUS, &ib_link->handle, &trans->handle, &ib_blob.bl_handle,
421 &ib_blob.bl_qd)) {
422 _php_ibase_error();
423 RETURN_FALSE;
424 }
425
426 if (_php_ibase_blob_info(ib_blob.bl_handle, &bl_info)) {
427 RETURN_FALSE;
428 }
429 if (isc_close_blob(IB_STATUS, &ib_blob.bl_handle)) {
430 _php_ibase_error();
431 RETURN_FALSE;
432 }
433 } else { /* null blob, all values to zero */
434 bl_info.max_segment = 0;
435 bl_info.num_segments = 0;
436 bl_info.total_length = 0;
437 bl_info.bl_stream = 0;
438 }
439
440 array_init(return_value);
441
442 add_index_long(return_value, 0, bl_info.total_length);
443 add_assoc_long(return_value, "length", bl_info.total_length);
444
445 add_index_long(return_value, 1, bl_info.num_segments);
446 add_assoc_long(return_value, "numseg", bl_info.num_segments);
447
448 add_index_long(return_value, 2, bl_info.max_segment);
449 add_assoc_long(return_value, "maxseg", bl_info.max_segment);
450
451 add_index_bool(return_value, 3, bl_info.bl_stream);
452 add_assoc_bool(return_value, "stream", bl_info.bl_stream);
453
454 add_index_bool(return_value, 4, (!ib_blob.bl_qd.gds_quad_high && !ib_blob.bl_qd.gds_quad_low));
455 add_assoc_bool(return_value, "isnull", (!ib_blob.bl_qd.gds_quad_high && !ib_blob.bl_qd.gds_quad_low));
456 }
457 /* }}} */
458
459 /* {{{ proto bool ibase_blob_echo([ resource link_identifier, ] string blob_id)
460 Output blob contents to browser */
PHP_FUNCTION(ibase_blob_echo)461 PHP_FUNCTION(ibase_blob_echo)
462 {
463 char *blob_id;
464 size_t blob_id_len;
465 zval *link = NULL;
466 ibase_db_link *ib_link;
467 ibase_trans *trans = NULL;
468 ibase_blob ib_blob_id = { 0, BLOB_OUTPUT };
469 char bl_data[IBASE_BLOB_SEG];
470 unsigned short seg_len;
471
472 RESET_ERRMSG;
473 PARSE_PARAMETERS;
474
475 PHP_IBASE_LINK_TRANS(link, ib_link, trans);
476
477 if (! _php_ibase_string_to_quad(blob_id, &ib_blob_id.bl_qd)) {
478 _php_ibase_module_error("Unrecognized BLOB ID");
479 RETURN_FALSE;
480 }
481
482 do {
483 if (isc_open_blob(IB_STATUS, &ib_link->handle, &trans->handle, &ib_blob_id.bl_handle,
484 &ib_blob_id.bl_qd)) {
485 break;
486 }
487
488 while (!isc_get_segment(IB_STATUS, &ib_blob_id.bl_handle, &seg_len, sizeof(bl_data), bl_data)
489 || IB_STATUS[1] == isc_segment) {
490 PHPWRITE(bl_data, seg_len);
491 }
492
493 if (IB_STATUS[0] && (IB_STATUS[1] != isc_segstr_eof)) {
494 break;
495 }
496
497 if (isc_close_blob(IB_STATUS, &ib_blob_id.bl_handle)) {
498 break;
499 }
500 RETURN_TRUE;
501 } while (0);
502
503 _php_ibase_error();
504 RETURN_FALSE;
505 }
506 /* }}} */
507
508 /* {{{ proto string ibase_blob_import([ resource link_identifier, ] resource file)
509 Create blob, copy file in it, and close it */
PHP_FUNCTION(ibase_blob_import)510 PHP_FUNCTION(ibase_blob_import)
511 {
512 zval *link = NULL, *file;
513 int size;
514 unsigned short b;
515 ibase_blob ib_blob = { 0, 0 };
516 ibase_db_link *ib_link;
517 ibase_trans *trans = NULL;
518 char bl_data[IBASE_BLOB_SEG];
519 php_stream *stream;
520
521 RESET_ERRMSG;
522
523 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "r|r",
524 (ZEND_NUM_ARGS()-1) ? &link : &file, &file)) {
525 RETURN_FALSE;
526 }
527
528 PHP_IBASE_LINK_TRANS(link, ib_link, trans);
529
530 php_stream_from_zval(stream, file);
531
532 do {
533 if (isc_create_blob(IB_STATUS, &ib_link->handle, &trans->handle, &ib_blob.bl_handle,
534 &ib_blob.bl_qd)) {
535 break;
536 }
537
538 for (size = 0; (b = php_stream_read(stream, bl_data, sizeof(bl_data))); size += b) {
539 if (isc_put_segment(IB_STATUS, &ib_blob.bl_handle, b, bl_data)) {
540 break;
541 }
542 }
543
544 if (isc_close_blob(IB_STATUS, &ib_blob.bl_handle)) {
545 break;
546 }
547 RETURN_NEW_STR(_php_ibase_quad_to_string(ib_blob.bl_qd));
548 } while (0);
549
550 _php_ibase_error();
551 RETURN_FALSE;
552 }
553 /* }}} */
554
555 #endif /* HAVE_IBASE */
556
557 /*
558 * Local variables:
559 * tab-width: 4
560 * c-basic-offset: 4
561 * End:
562 * vim600: sw=4 ts=4 fdm=marker
563 * vim<600: sw=4 ts=4
564 */
565