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