Skip to content

Commit 2223853

Browse files
committed
implement fseek for zip stream when possible with libzip 1.9.1
1 parent d8de067 commit 2223853

File tree

4 files changed

+129
-5
lines changed

4 files changed

+129
-5
lines changed

ext/zip/php_zip.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ extern zend_module_entry zip_module_entry;
3131
#define ZIP_OVERWRITE ZIP_TRUNCATE
3232
#endif
3333

34-
#define PHP_ZIP_VERSION "1.20.1"
34+
#define PHP_ZIP_VERSION "1.21.0"
3535

3636
#define ZIP_OPENBASEDIR_CHECKPATH(filename) php_check_open_basedir(filename)
3737

@@ -79,4 +79,6 @@ php_stream *php_stream_zip_open(struct zip *arch, struct zip_stat *sb, const cha
7979

8080
extern const php_stream_wrapper php_stream_zip_wrapper;
8181

82+
#define LIBZIP_ATLEAST(m,n,p) (((m<<16) + (n<<8) + p) <= ((LIBZIP_VERSION_MAJOR<<16) + (LIBZIP_VERSION_MINOR<<8) + LIBZIP_VERSION_MICRO))
83+
8284
#endif /* PHP_ZIP_H */

ext/zip/tests/oo_stream_seek.phpt

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
--TEST--
2+
getStream and seek
3+
--EXTENSIONS--
4+
zip
5+
--SKIPIF--
6+
<?php
7+
if(version_compare(ZipArchive::LIBZIP_VERSION, '1.9.1', '<')) die('skip libzip < 1.9.1');
8+
?>
9+
--FILE--
10+
<?php
11+
var_dump(ZipArchive::LIBZIP_VERSION);
12+
$file = __DIR__ . '/test.zip';
13+
$zip = new ZipArchive;
14+
if (!$zip->open($file)) {
15+
exit('failed');
16+
}
17+
echo "+ ZipArchive::getStream\n";
18+
$fp = $zip->getStream('bar');
19+
if(!$fp) exit("\n");
20+
var_dump($fp);
21+
22+
var_dump(fseek($fp, 1, SEEK_SET));
23+
var_dump(fread($fp, 2));
24+
var_dump(ftell($fp));
25+
var_dump(fseek($fp, 0, SEEK_SET));
26+
var_dump(fread($fp, 2));
27+
var_dump(ftell($fp));
28+
29+
fclose($fp);
30+
31+
echo "+ ZipArchive::getStream no supported\n";
32+
$fp = $zip->getStream('entry1.txt');
33+
if(!$fp) exit("\n");
34+
var_dump($fp);
35+
36+
var_dump(fseek($fp, 2, SEEK_SET));
37+
var_dump(fread($fp, 2));
38+
fclose($fp);
39+
40+
$zip->close();
41+
42+
43+
echo "+ Zip Stream\n";
44+
$fp = fopen('zip://' . __DIR__ . '/test.zip#bar', 'rb');
45+
if(!$fp) exit("\n");
46+
var_dump($fp);
47+
var_dump(fseek($fp, 1, SEEK_SET));
48+
var_dump(fread($fp, 2));
49+
var_dump(ftell($fp));
50+
var_dump(fseek($fp, 0, SEEK_SET));
51+
var_dump(fread($fp, 2));
52+
var_dump(ftell($fp));
53+
fclose($fp);
54+
55+
?>
56+
--EXPECTF--
57+
string(%d) "%s"
58+
+ ZipArchive::getStream
59+
resource(%d) of type (stream)
60+
int(0)
61+
string(2) "ar"
62+
int(3)
63+
int(0)
64+
string(2) "ba"
65+
int(2)
66+
+ ZipArchive::getStream no supported
67+
resource(%d) of type (stream)
68+
69+
Warning: fseek(): %s does not support seeking in %s
70+
int(-1)
71+
string(2) "en"
72+
+ Zip Stream
73+
resource(%d) of type (stream)
74+
int(0)
75+
string(2) "ar"
76+
int(3)
77+
int(0)
78+
string(2) "ba"
79+
int(2)

ext/zip/tests/stream_meta_data.phpt

+2-2
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ array(8) {
4545
["unread_bytes"]=>
4646
int(0)
4747
["seekable"]=>
48-
bool(false)
48+
bool(%s)
4949
["uri"]=>
5050
string(3) "foo"
5151
}
@@ -65,7 +65,7 @@ array(9) {
6565
["unread_bytes"]=>
6666
int(0)
6767
["seekable"]=>
68-
bool(false)
68+
bool(%s)
6969
["uri"]=>
7070
string(%d) "zip://%stest_with_comment.zip#foo"
7171
}

ext/zip/zip_stream.c

+45-2
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,35 @@ static int php_zip_ops_stat(php_stream *stream, php_stream_statbuf *ssb) /* {{{
197197
}
198198
/* }}} */
199199

200+
#if LIBZIP_ATLEAST(1,9,1)
201+
/* {{{ php_zip_ops_seek */
202+
static int php_zip_ops_seek(php_stream *stream, zend_off_t offset, int whence, zend_off_t *newoffset)
203+
{
204+
int ret = -1;
205+
STREAM_DATA_FROM_STREAM();
206+
207+
if (self->zf) {
208+
ret = zip_fseek(self->zf, offset, whence);
209+
*newoffset = zip_ftell(self->zf);
210+
}
211+
212+
return ret;
213+
}
214+
/* }}} */
215+
216+
/* with seek command */
217+
const php_stream_ops php_stream_zipio_seek_ops = {
218+
php_zip_ops_write, php_zip_ops_read,
219+
php_zip_ops_close, php_zip_ops_flush,
220+
"zip",
221+
php_zip_ops_seek, /* seek */
222+
NULL, /* cast */
223+
php_zip_ops_stat, /* stat */
224+
NULL /* set_option */
225+
};
226+
#endif
227+
228+
/* without seek command */
200229
const php_stream_ops php_stream_zipio_ops = {
201230
php_zip_ops_write, php_zip_ops_read,
202231
php_zip_ops_close, php_zip_ops_flush,
@@ -228,7 +257,14 @@ php_stream *php_stream_zip_open(struct zip *arch, struct zip_stat *sb, const cha
228257
self->zf = zf;
229258
self->stream = NULL;
230259
self->cursor = 0;
231-
stream = php_stream_alloc(&php_stream_zipio_ops, self, NULL, mode);
260+
#if LIBZIP_ATLEAST(1,9,1)
261+
if (zip_file_is_seekable(zf) > 0) {
262+
stream = php_stream_alloc(&php_stream_zipio_seek_ops, self, NULL, mode);
263+
} else
264+
#endif
265+
{
266+
stream = php_stream_alloc(&php_stream_zipio_ops, self, NULL, mode);
267+
}
232268
stream->orig_path = estrdup(sb->name);
233269
}
234270
}
@@ -307,7 +343,14 @@ php_stream *php_stream_zip_opener(php_stream_wrapper *wrapper,
307343
self->zf = zf;
308344
self->stream = NULL;
309345
self->cursor = 0;
310-
stream = php_stream_alloc(&php_stream_zipio_ops, self, NULL, mode);
346+
#if LIBZIP_ATLEAST(1,9,1)
347+
if (zip_file_is_seekable(zf) > 0) {
348+
stream = php_stream_alloc(&php_stream_zipio_seek_ops, self, NULL, mode);
349+
} else
350+
#endif
351+
{
352+
stream = php_stream_alloc(&php_stream_zipio_ops, self, NULL, mode);
353+
}
311354

312355
if (opened_path) {
313356
*opened_path = zend_string_init(path, strlen(path), 0);

0 commit comments

Comments
 (0)