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 35static int le_blob; 36 37static 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 51void 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 58int _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 75char *_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 90typedef 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 98int _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 131int _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 152static 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 */ 207PHP_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 */ 238PHP_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 */ 294PHP_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 */ 320PHP_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 346static 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 */ 384PHP_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 */ 392PHP_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 */ 400PHP_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 */ 476PHP_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 */ 539PHP_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