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