├── CREDITS ├── EXPERIMENTAL ├── LICENSE ├── README.md ├── config.w32 ├── php_wfio.c ├── php_wfio.h ├── readdirw.c ├── readdirw.h └── tests ├── 001.phpt ├── chdir.phpt ├── compare_large_stat.phpt ├── compare_large_stat_int64.phpt ├── compare_stat.phpt ├── compare_stat_fstat.phpt ├── filefuncs.phpt ├── fopen.phpt ├── mkdir.phpt ├── mkdir_UTF8.phpt ├── nonascii_cwd.phpt └── scandir_crash_on_absent.phpt /CREDITS: -------------------------------------------------------------------------------- 1 | wfio 2 | kenji uno -------------------------------------------------------------------------------- /EXPERIMENTAL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenjiuno/php-wfio/d29f1073230a0bbb644ecd946668030a0c10f67f/EXPERIMENTAL -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, kenjiuno 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, this 11 | list of conditions and the following disclaimer in the documentation and/or 12 | other materials provided with the distribution. 13 | 14 | * Neither the name of the {organization} nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 22 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 25 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | php-wfio 2 | ======== 3 | Unicode(UTF-8 only) filename support for PHP 5.4, 5.5, 5.6, and 7.0 (x86 and x64) on Windows 4 | 5 | **Note:** now PHP 7.1 can handle UTF-8 filepath by setting [internal_encoding](http://php.net/manual/en/ini.core.php#ini.internal-encoding) to UTF-8. 6 | 7 | Edit your php.ini: 8 | 9 | ```ini 10 | ; PHP's default character set is set to UTF-8. 11 | ; http://php.net/default-charset 12 | default_charset = "UTF-8" 13 | 14 | ; PHP internal character encoding is set to empty. 15 | ; If empty, default_charset is used. 16 | ; http://php.net/internal-encoding 17 | ;internal_encoding = 18 | ``` 19 | 20 | Install 21 | ------- 22 | Get binary: https://github.com/kenjiuno/php-wfio/releases 23 | 24 | Put php_wfio.dll into php\ext folder 25 | 26 | Edit your php.ini 27 | 28 | [PHP] 29 | extension_dir = "ext" ; Uncomment this line 30 | extension=php_wfio.dll ; Add this line 31 | 32 | Run php.exe -m 33 | 34 | H:\php-5.4.25>php.exe -m 35 | [PHP Modules] 36 | ... 37 | wfio 38 | ... 39 | 40 | [Zend Modules] 41 | 42 | 43 | Code Samples 44 | ------------ 45 | About file access: 46 | 47 | $file = wfio_fopen8("多国語.txt", "rb"); // in UTF-8 48 | .... 49 | fclose($file); 50 | 51 | Or you can use stream wrapper: 52 | 53 | $file = fopen("wfio://多国語.txt", "rb"); // in UTF-8 54 | .... 55 | fclose($file); 56 | 57 | dirstream is also supported: 58 | 59 | $d = opendir("wfio://C:\\Windows"); 60 | .... 61 | closedir($d); 62 | 63 | "wfio://" supports: 64 | 65 | fopen("wfio://多国語.txt") 66 | fwrite 67 | fread 68 | stat("wfio://filename") 69 | fclose 70 | 71 | is_file 72 | is_dir 73 | file_exists 74 | 75 | opendir("wfio://C:\\Windows") 76 | readdir 77 | closedir 78 | 79 | rename("wfio://oldname", "wfio://newname") 80 | copy("wfio://source", "wfio://dest") 81 | unlink("wfio://filename") 82 | mkdir("wfio://pathname") 83 | rmdir("wfio://dirname") 84 | 85 | scandir("wfio://directory") 86 | file_get_contents("wfio://filename") 87 | file_put_contents("wfio://filename", "...") 88 | 89 | No chdir support 90 | ---------------- 91 | 92 | * Current directory is process's property. 93 | * So, keep your path to fullpath always like "wfio://C:\\dir1\\dir2\\dir3\\filename". 94 | * Use wfio_getcwd8 for getting current directory 95 | * Use wfio_path_combine to hold your subdir in fullpath format. 96 | 97 | My build options 98 | ---------------- 99 | 100 | rem TS ThreadSafety "Release_TS" config.nice.bat 101 | 102 | cscript /nologo configure.js "--disable-all" "--enable-cli" "--disable-debug" "--enable-com-dotnet" "--with-wfio=shared" "--enable-cgi" "--enable-isapi" %* 103 | 104 | rem NTS NonThreadSafety "Release" config.nts.bat 105 | 106 | cscript /nologo configure.js "--disable-all" "--disable-zts" "--enable-cli" "--disable-debug" "--enable-com-dotnet" "--with-wfio=shared" "--enable-cgi" "--enable-isapi" %* 107 | 108 | twfio.bat 109 | 110 | SET TEST_PHP_EXECUTABLE=H:\php-sdk\php54dev\vc9\x86\php5.4\Release_TS\php.exe 111 | Release_TS\php.exe run-tests.php ext\wfio\tests 112 | 113 | twfio-nts.bat 114 | 115 | SET TEST_PHP_EXECUTABLE=H:\php-sdk\php54dev\vc9\x86\php5.4\Release\php.exe 116 | Release\php.exe run-tests.php ext\wfio\tests 117 | 118 | Thread Safety 119 | ------------- 120 | Invoke "php.exe -i" to check it. 121 | 122 | NTS(Non Thread Safety): 123 | 124 | php.exe -i 2> NUL | find "Thread Safety" 125 | Thread Safety => disabled 126 | 127 | TS(Thread Safety): 128 | 129 | php.exe -i 2> NUL | find "Thread Safety" 130 | Thread Safety => enabled 131 | -------------------------------------------------------------------------------- /config.w32: -------------------------------------------------------------------------------- 1 | // $Id$ 2 | // vim:ft=javascript 3 | 4 | ARG_WITH("wfio", "wfio support", "no"); 5 | 6 | if (PHP_WFIO != "no") { 7 | EXTENSION("wfio", "php_wfio.c readdirw.c"); 8 | } 9 | -------------------------------------------------------------------------------- /php_wfio.c: -------------------------------------------------------------------------------- 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 | | Author: kenji uno | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | /* $Id$ */ 20 | 21 | #ifdef HAVE_CONFIG_H 22 | #include "config.h" 23 | #endif 24 | 25 | #include "php.h" 26 | #include "php_ini.h" 27 | #include "ext/standard/info.h" 28 | #include "ext/standard/php_filestat.h" 29 | #include "php_wfio.h" 30 | #include "readdirw.h" 31 | #include 32 | #pragma comment(lib, "shlwapi") 33 | 34 | struct php_wfio_stream_data_t { 35 | FILE *pf; 36 | }; 37 | 38 | /* If you declare any globals in php_wfio.h uncomment this: 39 | ZEND_DECLARE_MODULE_GLOBALS(wfio) 40 | */ 41 | 42 | /* True global resources - no need for thread safety here */ 43 | static int le_wfio; 44 | 45 | ZEND_BEGIN_ARG_INFO(arginfo_wfio_fopen8, 0) 46 | ZEND_ARG_INFO(0, file) 47 | ZEND_ARG_INFO(0, mode) 48 | ZEND_END_ARG_INFO() 49 | 50 | ZEND_BEGIN_ARG_INFO(arginfo_wfio_getcwd8, 0) 51 | ZEND_END_ARG_INFO() 52 | 53 | ZEND_BEGIN_ARG_INFO(arginfo_wfio_path2utf8, 0) 54 | ZEND_ARG_INFO(0, path) 55 | ZEND_END_ARG_INFO() 56 | 57 | ZEND_BEGIN_ARG_INFO(arginfo_wfio_path_from_utf8, 0) 58 | ZEND_ARG_INFO(0, path) 59 | ZEND_END_ARG_INFO() 60 | 61 | ZEND_BEGIN_ARG_INFO(arginfo_wfio_path_combine, 0) 62 | ZEND_ARG_INFO(0, dir) 63 | ZEND_ARG_INFO(0, file) 64 | ZEND_END_ARG_INFO() 65 | 66 | /* {{{ wfio_functions[] 67 | * 68 | * Every user visible function must have an entry in wfio_functions[]. 69 | */ 70 | const zend_function_entry wfio_functions[] = { 71 | PHP_FE(wfio_fopen8, arginfo_wfio_fopen8) 72 | PHP_FE(wfio_getcwd8, arginfo_wfio_getcwd8) 73 | PHP_FE(wfio_path2utf8, arginfo_wfio_path2utf8) 74 | PHP_FE(wfio_path_from_utf8, arginfo_wfio_path_from_utf8) 75 | PHP_FE(wfio_path_combine, arginfo_wfio_path_combine) 76 | PHP_FE_END /* Must be the last line in wfio_functions[] */ 77 | }; 78 | /* }}} */ 79 | 80 | /* {{{ wfio_module_entry 81 | */ 82 | zend_module_entry wfio_module_entry = { 83 | #if ZEND_MODULE_API_NO >= 20010901 84 | STANDARD_MODULE_HEADER, 85 | #endif 86 | "wfio", 87 | wfio_functions, 88 | PHP_MINIT(wfio), 89 | PHP_MSHUTDOWN(wfio), 90 | PHP_RINIT(wfio), /* Replace with NULL if there's nothing to do at request start */ 91 | PHP_RSHUTDOWN(wfio), /* Replace with NULL if there's nothing to do at request end */ 92 | PHP_MINFO(wfio), 93 | #if ZEND_MODULE_API_NO >= 20010901 94 | "0.1", /* Replace with version number for your extension */ 95 | #endif 96 | STANDARD_MODULE_PROPERTIES 97 | }; 98 | /* }}} */ 99 | 100 | #ifdef COMPILE_DL_WFIO 101 | ZEND_GET_MODULE(wfio) 102 | #endif 103 | 104 | /* {{{ PHP_INI 105 | */ 106 | /* Remove comments and fill if you need to have entries in php.ini 107 | PHP_INI_BEGIN() 108 | STD_PHP_INI_ENTRY("wfio.global_value", "42", PHP_INI_ALL, OnUpdateLong, global_value, zend_wfio_globals, wfio_globals) 109 | STD_PHP_INI_ENTRY("wfio.global_string", "foobar", PHP_INI_ALL, OnUpdateString, global_string, zend_wfio_globals, wfio_globals) 110 | PHP_INI_END() 111 | */ 112 | /* }}} */ 113 | 114 | /* {{{ php_wfio_init_globals 115 | */ 116 | /* Uncomment this function if you have INI entries 117 | static void php_wfio_init_globals(zend_wfio_globals *wfio_globals) 118 | { 119 | wfio_globals->global_value = 0; 120 | wfio_globals->global_string = NULL; 121 | } 122 | */ 123 | /* }}} */ 124 | 125 | /* {{{ PHP_MINIT_FUNCTION 126 | */ 127 | PHP_MINIT_FUNCTION(wfio) 128 | { 129 | php_register_url_stream_wrapper("wfio", &php_stream_wfio_wrapper TSRMLS_CC); 130 | 131 | /* If you have INI entries, uncomment these lines 132 | REGISTER_INI_ENTRIES(); 133 | */ 134 | return SUCCESS; 135 | } 136 | /* }}} */ 137 | 138 | /* {{{ PHP_MSHUTDOWN_FUNCTION 139 | */ 140 | PHP_MSHUTDOWN_FUNCTION(wfio) 141 | { 142 | php_unregister_url_stream_wrapper("wfio" TSRMLS_CC); 143 | 144 | /* uncomment this line if you have INI entries 145 | UNREGISTER_INI_ENTRIES(); 146 | */ 147 | return SUCCESS; 148 | } 149 | /* }}} */ 150 | 151 | /* Remove if there's nothing to do at request start */ 152 | /* {{{ PHP_RINIT_FUNCTION 153 | */ 154 | PHP_RINIT_FUNCTION(wfio) 155 | { 156 | return SUCCESS; 157 | } 158 | /* }}} */ 159 | 160 | /* Remove if there's nothing to do at request end */ 161 | /* {{{ PHP_RSHUTDOWN_FUNCTION 162 | */ 163 | PHP_RSHUTDOWN_FUNCTION(wfio) 164 | { 165 | return SUCCESS; 166 | } 167 | /* }}} */ 168 | 169 | /* {{{ PHP_MINFO_FUNCTION 170 | */ 171 | PHP_MINFO_FUNCTION(wfio) 172 | { 173 | php_info_print_table_start(); 174 | php_info_print_table_header(2, "wfio support", "enabled"); 175 | php_info_print_table_end(); 176 | 177 | /* Remove comments if you have entries in php.ini 178 | DISPLAY_INI_ENTRIES(); 179 | */ 180 | } 181 | /* }}} */ 182 | 183 | 184 | static int wfio_realpathw(wchar_t *relpath, size_t relpath_len TSRMLS_DC) { 185 | char *p; 186 | char workdir[MAXPATHLEN] = {0}; 187 | wchar_t workdirw[MAX_PATH] = {0}; 188 | wchar_t newpathw[MAX_PATH] = {0}; 189 | 190 | if (relpath[0] == L'\\' || relpath[0] == L'/') 191 | return 0; 192 | 193 | p = VCWD_GETCWD(workdir, MAXPATHLEN); 194 | 195 | if (p != NULL) { 196 | MultiByteToWideChar(CP_ACP, 0, workdir, MAXPATHLEN, workdirw, MAX_PATH); 197 | PathCombineW(newpathw, workdirw, relpath); 198 | wcsncpy(relpath, newpathw, relpath_len); 199 | return 0; 200 | } else { 201 | return -1; 202 | } 203 | } 204 | 205 | /* Remove the following function when you have succesfully modified config.m4 206 | so that your module can be compiled into PHP, it exists only for testing 207 | purposes. */ 208 | 209 | static size_t php_wfiop_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) 210 | { 211 | struct php_wfio_stream_data_t *self = (struct php_wfio_stream_data_t *) stream->abstract; 212 | size_t read; 213 | 214 | read = fread(buf, 1, count, self->pf); 215 | 216 | if (feof(self->pf) != 0) { 217 | stream->eof = 1; 218 | } 219 | 220 | return (read < 0) ? 0 : read; 221 | } 222 | 223 | static size_t php_wfiop_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) 224 | { 225 | struct php_wfio_stream_data_t *self = (struct php_wfio_stream_data_t *) stream->abstract; 226 | int wrote; 227 | 228 | wrote = fwrite((char *) buf, 1, count, self->pf); 229 | 230 | return (wrote < 0) ? 0 : wrote; 231 | } 232 | 233 | #ifdef ZEND_ENGINE_3 234 | static int php_wfiop_seek(php_stream *stream, zend_off_t offset, int whence, zend_off_t *newoffs TSRMLS_DC) 235 | #else 236 | static int php_wfiop_seek(php_stream *stream, off_t offset, int whence, off_t *newoffs TSRMLS_DC) 237 | #endif 238 | { 239 | struct php_wfio_stream_data_t *self = (struct php_wfio_stream_data_t *) stream->abstract; 240 | 241 | assert(self != NULL); 242 | 243 | _fseeki64(self->pf, offset, whence); 244 | 245 | #ifdef ZEND_ENGINE_3 246 | *newoffs = (zend_off_t) _ftelli64(self->pf); 247 | #else 248 | *newoffs = (off_t) _ftelli64(self->pf); 249 | #endif 250 | 251 | return (*newoffs < 0) ? -1 : 0; 252 | } 253 | 254 | static int php_wfiop_stat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC) 255 | { 256 | // by php's fstat 257 | struct php_wfio_stream_data_t *self = (struct php_wfio_stream_data_t *) stream->abstract; 258 | #ifdef _WIN64 259 | struct _stat64i32 sb; 260 | #else 261 | struct _stat32 sb; 262 | #endif 263 | int r; 264 | 265 | if (!self) { 266 | return -1; 267 | } 268 | 269 | r = _fstat(_fileno(self->pf), &sb); 270 | if (r == 0) { 271 | ssb->sb.st_gid = sb.st_gid; 272 | ssb->sb.st_atime = sb.st_atime; 273 | ssb->sb.st_ctime = sb.st_ctime; 274 | ssb->sb.st_dev = sb.st_dev; 275 | ssb->sb.st_ino = sb.st_ino; 276 | ssb->sb.st_mode = sb.st_mode; 277 | ssb->sb.st_mtime = sb.st_mtime; 278 | ssb->sb.st_nlink = sb.st_nlink; 279 | ssb->sb.st_rdev = sb.st_rdev; 280 | ssb->sb.st_size = sb.st_size; 281 | ssb->sb.st_uid = sb.st_uid; 282 | } 283 | 284 | return r; 285 | } 286 | 287 | static int php_wfiop_close(php_stream *stream, int close_handle TSRMLS_DC) 288 | { 289 | struct php_wfio_stream_data_t *self = (struct php_wfio_stream_data_t *) stream->abstract; 290 | int ret = EOF; 291 | 292 | if (close_handle) { 293 | if (self->pf != NULL) { 294 | ret = fclose(self->pf); 295 | self->pf = NULL; 296 | } 297 | } 298 | efree(self); 299 | 300 | return ret; 301 | } 302 | 303 | static int php_wfiop_flush(php_stream *stream TSRMLS_DC) 304 | { 305 | struct php_wfio_stream_data_t *self = (struct php_wfio_stream_data_t *) stream->abstract; 306 | 307 | return fflush(self->pf); 308 | } 309 | 310 | php_stream_ops php_stream_wfio_ops = { 311 | php_wfiop_write, php_wfiop_read, 312 | php_wfiop_close, php_wfiop_flush, 313 | "WFIO", 314 | php_wfiop_seek, 315 | NULL, /* cast */ 316 | php_wfiop_stat, /* stat */ 317 | NULL /* set_option */ 318 | }; 319 | 320 | #ifdef ZEND_ENGINE_3 321 | php_stream *php_wfio_stream_opener(php_stream_wrapper *wrapper, const char *path, const char *mode, int options, 322 | zend_string **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC) 323 | #else 324 | php_stream *php_wfio_stream_opener(php_stream_wrapper *wrapper, const char *path, const char *mode, int options, 325 | char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC) 326 | #endif 327 | { 328 | struct php_wfio_stream_data_t *self; 329 | php_stream *stream; 330 | 331 | wchar_t pathw[WFIO_MAX_PATH] = {0}; 332 | wchar_t fp_pathw[WFIO_MAX_PATH] = {0}; 333 | wchar_t modew[WFIO_MAX_PATH] = {0}; 334 | 335 | if (strncasecmp("wfio://", path, 7) == 0) { 336 | path += 7; 337 | } 338 | 339 | MultiByteToWideChar(CP_UTF8, 0, path, -1, pathw, WFIO_MAX_PATH); 340 | MultiByteToWideChar(CP_UTF8, 0, mode, -1, modew, WFIO_MAX_PATH); 341 | 342 | wfio_realpathw(pathw, WFIO_MAX_PATH TSRMLS_CC); 343 | 344 | self = emalloc(sizeof(*self)); 345 | self->pf = _wfopen(pathw, modew); 346 | 347 | if (self->pf != NULL) { 348 | stream = php_stream_alloc_rel(&php_stream_wfio_ops, self, 0, mode); 349 | if (stream) { 350 | stream->flags |= PHP_STREAM_FLAG_NO_BUFFER; 351 | return stream; 352 | } 353 | 354 | fclose(self->pf); 355 | } 356 | 357 | efree(self); 358 | if (options & REPORT_ERRORS) { 359 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "wfio_fopen8 failed"); 360 | } 361 | 362 | return NULL; 363 | } 364 | 365 | static int php_wfio_url_stater(php_stream_wrapper *wrapper, const char *url, int flags, php_stream_statbuf *ssb, php_stream_context *context TSRMLS_DC) 366 | { 367 | wchar_t urlw[WFIO_MAX_PATH] = {0}; 368 | struct _stat64 sb; 369 | int cch; 370 | 371 | if (strncmp(url, "wfio://", 7) == 0) { 372 | url += 7; 373 | } 374 | 375 | cch = strlen(url); 376 | if (cch > 3 && url[cch -1] == '/' && url[cch -2] != ':') 377 | cch--; 378 | 379 | MultiByteToWideChar(CP_UTF8, 0, url, cch, urlw, WFIO_MAX_PATH); 380 | 381 | wfio_realpathw(urlw, WFIO_MAX_PATH TSRMLS_CC); 382 | 383 | if (_wstat64(urlw, &sb) != 0) 384 | return -1; 385 | 386 | ssb->sb.st_gid = sb.st_gid; 387 | ssb->sb.st_atime = (time_t)sb.st_atime; 388 | ssb->sb.st_ctime = (time_t)sb.st_ctime; 389 | ssb->sb.st_dev = sb.st_dev; 390 | ssb->sb.st_ino = sb.st_ino; 391 | ssb->sb.st_mode = sb.st_mode; 392 | ssb->sb.st_mtime = (time_t)sb.st_mtime; 393 | ssb->sb.st_nlink = sb.st_nlink; 394 | ssb->sb.st_rdev = sb.st_rdev; 395 | ssb->sb.st_size = (off_t)sb.st_size; 396 | ssb->sb.st_uid = sb.st_uid; 397 | 398 | return 0; 399 | } 400 | 401 | /* {{{ plain files opendir/readdir implementation */ 402 | static size_t php_wfio_dirstream_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) 403 | { 404 | DIRW *dir = (DIRW*)stream->abstract; 405 | /* avoid libc5 readdir problems */ 406 | struct direntw entry; 407 | struct direntw *result = (struct direntw *)&entry; 408 | php_stream_dirent *ent = (php_stream_dirent*)buf; 409 | 410 | /* avoid problems if someone mis-uses the stream */ 411 | if (count != sizeof(php_stream_dirent)) 412 | return 0; 413 | 414 | if (readdirw_r(dir, &entry, &result) == 0 && result != NULL) { 415 | WideCharToMultiByte(CP_UTF8, 0, result->d_name, -1, ent->d_name, sizeof(ent->d_name), NULL, NULL); 416 | return sizeof(php_stream_dirent); 417 | } 418 | return 0; 419 | } 420 | 421 | static int php_wfio_dirstream_close(php_stream *stream, int close_handle TSRMLS_DC) 422 | { 423 | return closedirw((DIRW *)stream->abstract); 424 | } 425 | 426 | #ifdef ZEND_ENGINE_3 427 | static int php_wfio_dirstream_rewind(php_stream *stream, zend_off_t offset, int whence, zend_off_t *newoffs TSRMLS_DC) 428 | #else 429 | static int php_wfio_dirstream_rewind(php_stream *stream, off_t offset, int whence, off_t *newoffs TSRMLS_DC) 430 | #endif 431 | { 432 | rewinddirw((DIRW *)stream->abstract); 433 | return 0; 434 | } 435 | 436 | static php_stream_ops php_wfio_dirstream_ops = { 437 | NULL, php_wfio_dirstream_read, 438 | php_wfio_dirstream_close, NULL, 439 | "wfio_dir", 440 | php_wfio_dirstream_rewind, 441 | NULL, /* cast */ 442 | php_wfiop_stat, /* stat */ 443 | NULL /* set_option */ 444 | }; 445 | 446 | #ifdef ZEND_ENGINE_3 447 | static php_stream *php_wfio_dir_opener(php_stream_wrapper *wrapper, const char *path, const char *mode, 448 | int options, zend_string **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC) 449 | #else 450 | static php_stream *php_wfio_dir_opener(php_stream_wrapper *wrapper, const char *path, const char *mode, 451 | int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC) 452 | #endif 453 | { 454 | DIRW *dir; 455 | php_stream *stream = NULL; 456 | wchar_t pathw[WFIO_MAX_PATH] = {0}; 457 | 458 | if (strncmp(path, "wfio://", 7) == 0) { 459 | path += 7; 460 | } 461 | 462 | MultiByteToWideChar(CP_UTF8, 0, path, -1, pathw, WFIO_MAX_PATH); 463 | 464 | wfio_realpathw(pathw, WFIO_MAX_PATH TSRMLS_CC); 465 | 466 | dir = opendirw(pathw); 467 | 468 | #ifdef PHP_WIN32 469 | if (!dir) { 470 | php_win32_docref2_from_error(GetLastError(), path, path TSRMLS_CC); 471 | } 472 | 473 | if (dir && dir->finished) { 474 | closedirw(dir); 475 | dir = NULL; 476 | } 477 | #endif 478 | if (dir) { 479 | stream = php_stream_alloc(&php_wfio_dirstream_ops, dir, 0, mode); 480 | if (stream == NULL) 481 | closedirw(dir); 482 | } 483 | 484 | return stream; 485 | } 486 | 487 | static int php_wfio_unlink(php_stream_wrapper *wrapper, const char *url, int options, php_stream_context *context TSRMLS_DC) 488 | { 489 | int ret; 490 | wchar_t urlw[WFIO_MAX_PATH] = {0}; 491 | 492 | if (strncmp(url, "wfio://", 7) == 0) { 493 | url += 7; 494 | } 495 | 496 | MultiByteToWideChar(CP_UTF8, 0, url, -1, urlw, WFIO_MAX_PATH); 497 | 498 | wfio_realpathw(urlw, WFIO_MAX_PATH TSRMLS_CC); 499 | 500 | ret = _wunlink(urlw); 501 | if (ret == -1) { 502 | if (options & REPORT_ERRORS) { 503 | php_error_docref1(NULL TSRMLS_CC, url, E_WARNING, "%s", strerror(errno)); 504 | } 505 | return 0; 506 | } 507 | 508 | /* Clear stat cache (and realpath cache) */ 509 | php_clear_stat_cache(1, NULL, 0 TSRMLS_CC); 510 | 511 | return 1; 512 | } 513 | 514 | static int php_wfio_rename(php_stream_wrapper *wrapper, const char *url_from, const char *url_to, int options, php_stream_context *context TSRMLS_DC) 515 | { 516 | int ret; 517 | wchar_t urlw_from[WFIO_MAX_PATH] = {0}; 518 | wchar_t urlw_to[WFIO_MAX_PATH] = {0}; 519 | 520 | if (!url_from || !url_to) { 521 | return 0; 522 | } 523 | 524 | if (strncmp(url_from, "wfio://", 7) == 0) { 525 | url_from += 7; 526 | } 527 | 528 | if (strncmp(url_to, "wfio://", 7) == 0) { 529 | url_to += 7; 530 | } 531 | 532 | MultiByteToWideChar(CP_UTF8, 0, url_from, -1, urlw_from, WFIO_MAX_PATH); 533 | MultiByteToWideChar(CP_UTF8, 0, url_to, -1, urlw_to, WFIO_MAX_PATH); 534 | 535 | wfio_realpathw(urlw_from, WFIO_MAX_PATH TSRMLS_CC); 536 | wfio_realpathw(urlw_to, WFIO_MAX_PATH TSRMLS_CC); 537 | 538 | ret = _wrename(urlw_from, urlw_to); 539 | 540 | if (ret == -1) { 541 | php_win32_docref2_from_error(GetLastError(), url_from, url_to TSRMLS_CC); 542 | return 0; 543 | } 544 | 545 | /* Clear stat cache (and realpath cache) */ 546 | php_clear_stat_cache(1, NULL, 0 TSRMLS_CC); 547 | 548 | return 1; 549 | } 550 | 551 | static int php_wfio_mkdir(php_stream_wrapper *wrapper, const char *dir, int mode, int options, php_stream_context *context TSRMLS_DC) 552 | { 553 | int ret, recursive = options & PHP_STREAM_MKDIR_RECURSIVE; 554 | wchar_t dirw[WFIO_MAX_PATH] = {0}; 555 | 556 | if (strncmp(dir, "wfio://", 7) == 0) { 557 | dir += 7; 558 | } 559 | 560 | MultiByteToWideChar(CP_UTF8, 0, dir, -1, dirw, WFIO_MAX_PATH); 561 | 562 | wfio_realpathw(dirw, WFIO_MAX_PATH TSRMLS_CC); 563 | 564 | ret = _wmkdir(dirw); 565 | if (ret < 0) { 566 | /* Failure */ 567 | return 0; 568 | } else { 569 | /* Success */ 570 | return 1; 571 | } 572 | } 573 | 574 | static int php_wfio_rmdir(php_stream_wrapper *wrapper, const char *url, int options, php_stream_context *context TSRMLS_DC) 575 | { 576 | int url_len = strlen(url); 577 | wchar_t urlw[WFIO_MAX_PATH] = {0}; 578 | 579 | if (strncmp(url, "wfio://", 7) == 0) { 580 | url += 7; 581 | } 582 | 583 | MultiByteToWideChar(CP_UTF8, 0, url, -1, urlw, WFIO_MAX_PATH); 584 | 585 | wfio_realpathw(urlw, WFIO_MAX_PATH TSRMLS_CC); 586 | 587 | if (_wrmdir(urlw) < 0) { 588 | php_error_docref1(NULL TSRMLS_CC, url, E_WARNING, "%s", strerror(errno)); 589 | return 0; 590 | } 591 | 592 | /* Clear stat cache (and realpath cache) */ 593 | php_clear_stat_cache(1, NULL, 0 TSRMLS_CC); 594 | 595 | return 1; 596 | } 597 | 598 | PHP_FUNCTION(wfio_fopen8) 599 | { 600 | char *fname = NULL; 601 | int fname_len = 0; 602 | char *fmode = NULL; 603 | int fmode_len = 0; 604 | php_stream *stream = NULL; 605 | int flags = REPORT_ERRORS; 606 | 607 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &fname, &fname_len, &fmode, &fmode_len) == FAILURE) { 608 | return; 609 | } 610 | 611 | stream = php_wfio_stream_opener(NULL, fname, fmode, flags, NULL, NULL STREAMS_CC TSRMLS_CC); 612 | 613 | if (!stream) { 614 | RETURN_FALSE; 615 | } 616 | php_stream_to_zval(stream, return_value); 617 | } 618 | 619 | /* {{{ proto mixed getcwd(void) 620 | Gets the current directory */ 621 | PHP_FUNCTION(wfio_getcwd8) 622 | { 623 | wchar_t pathw[WFIO_MAX_PATH] = {0}; 624 | char path[MAXPATHLEN] = {0}; 625 | char buffer[MAXPATHLEN] = {0}; 626 | char *p; 627 | 628 | if (zend_parse_parameters_none() == FAILURE) { 629 | return; 630 | } 631 | 632 | p = VCWD_GETCWD(buffer, MAXPATHLEN); 633 | if (p != NULL) { 634 | MultiByteToWideChar(CP_ACP, 0, buffer, MAXPATHLEN, pathw, WFIO_MAX_PATH); 635 | WideCharToMultiByte(CP_UTF8, 0, pathw, -1, path, MAXPATHLEN, NULL, NULL); 636 | #ifdef ZEND_ENGINE_3 637 | RETURN_STRING(path); 638 | #else 639 | RETURN_STRING(path, 1); 640 | #endif 641 | } else { 642 | RETURN_FALSE; 643 | } 644 | } 645 | /* }}} */ 646 | 647 | PHP_FUNCTION(wfio_path2utf8) 648 | { 649 | char *path = NULL; 650 | int path_len = 0; 651 | wchar_t pathw[WFIO_MAX_PATH] = {0}; 652 | char fp_path[WFIO_MAX_PATH] = {0}; 653 | 654 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &path, &path_len) == FAILURE) { 655 | return; 656 | } 657 | 658 | MultiByteToWideChar(CP_ACP, 0, path, path_len, pathw, WFIO_MAX_PATH); 659 | WideCharToMultiByte(CP_UTF8, 0, pathw, -1, fp_path, MAXPATHLEN, NULL, NULL); 660 | 661 | #ifdef ZEND_ENGINE_3 662 | RETURN_STRING(fp_path); 663 | #else 664 | RETURN_STRING(fp_path, 1); 665 | #endif 666 | } 667 | 668 | PHP_FUNCTION(wfio_path_from_utf8) 669 | { 670 | char *path = NULL; 671 | int path_len = 0; 672 | wchar_t pathw[WFIO_MAX_PATH] = {0}; 673 | char fp_path[WFIO_MAX_PATH] = {0}; 674 | BOOL fUsedDefaultChar = FALSE; 675 | 676 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &path, &path_len) == FAILURE) { 677 | return; 678 | } 679 | 680 | MultiByteToWideChar(CP_UTF8, 0, path, path_len, pathw, WFIO_MAX_PATH); 681 | WideCharToMultiByte(CP_ACP, 0, pathw, -1, fp_path, MAXPATHLEN, NULL, &fUsedDefaultChar); 682 | 683 | if (fUsedDefaultChar) { 684 | RETURN_FALSE; 685 | } 686 | #ifdef ZEND_ENGINE_3 687 | RETURN_STRING(fp_path); 688 | #else 689 | RETURN_STRING(fp_path, 1); 690 | #endif 691 | } 692 | 693 | PHP_FUNCTION(wfio_path_combine) 694 | { 695 | char *dir = NULL; 696 | int dir_len = 0; 697 | char *file = NULL; 698 | int file_len = 0; 699 | wchar_t dirw[WFIO_MAX_PATH] = {0}; 700 | wchar_t filew[WFIO_MAX_PATH] = {0}; 701 | wchar_t destw[WFIO_MAX_PATH] = {0}; 702 | char dest[WFIO_MAX_PATH] = {0}; 703 | 704 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &dir, &dir_len, &file, &file_len) == FAILURE) { 705 | return; 706 | } 707 | 708 | MultiByteToWideChar(CP_UTF8, 0, dir, dir_len, dirw, WFIO_MAX_PATH); 709 | MultiByteToWideChar(CP_UTF8, 0, file, file_len, filew, WFIO_MAX_PATH); 710 | 711 | if (file[0] == L'\\' || file[0] == L'/') { 712 | wcsncpy(destw, filew, WFIO_MAX_PATH); 713 | } 714 | else if (!PathCombineW(destw, dirw, filew)) { 715 | RETURN_FALSE; 716 | } 717 | 718 | WideCharToMultiByte(CP_UTF8, 0, destw, -1, dest, MAXPATHLEN, NULL, NULL); 719 | 720 | #ifdef ZEND_ENGINE_3 721 | RETURN_STRING(dest); 722 | #else 723 | RETURN_STRING(dest, 1); 724 | #endif 725 | } 726 | 727 | static php_stream_wrapper_ops wfio_stream_wops = { 728 | php_wfio_stream_opener, 729 | NULL, /* close */ 730 | NULL, /* stat */ 731 | php_wfio_url_stater, /* stat_url */ 732 | php_wfio_dir_opener, /* opendir */ 733 | "WFIO", 734 | php_wfio_unlink, /* unlink */ 735 | php_wfio_rename, /* rename */ 736 | php_wfio_mkdir, /* mkdir */ 737 | php_wfio_rmdir, /* rmdir */ 738 | }; 739 | 740 | php_stream_wrapper php_stream_wfio_wrapper = { 741 | &wfio_stream_wops, 742 | NULL, 743 | 0, /* is_url */ 744 | }; 745 | 746 | /* 747 | * Local variables: 748 | * tab-width: 4 749 | * c-basic-offset: 4 750 | * End: 751 | * vim600: noet sw=4 ts=4 fdm=marker 752 | * vim<600: noet sw=4 ts=4 753 | */ 754 | -------------------------------------------------------------------------------- /php_wfio.h: -------------------------------------------------------------------------------- 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 | | Author: kenji uno | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | /* $Id$ */ 20 | 21 | #ifndef PHP_WFIO_H 22 | #define PHP_WFIO_H 23 | 24 | #ifndef WFIO_MAX_PATH 25 | #define WFIO_MAX_PATH 1024 26 | #endif 27 | 28 | extern zend_module_entry wfio_module_entry; 29 | #define phpext_wfio_ptr &wfio_module_entry 30 | 31 | #ifdef PHP_WIN32 32 | # define PHP_WFIO_API __declspec(dllexport) 33 | #elif defined(__GNUC__) && __GNUC__ >= 4 34 | # define PHP_WFIO_API __attribute__ ((visibility("default"))) 35 | #else 36 | # define PHP_WFIO_API 37 | #endif 38 | 39 | #ifdef ZTS 40 | #include "TSRM.h" 41 | #endif 42 | 43 | PHP_MINIT_FUNCTION(wfio); 44 | PHP_MSHUTDOWN_FUNCTION(wfio); 45 | PHP_RINIT_FUNCTION(wfio); 46 | PHP_RSHUTDOWN_FUNCTION(wfio); 47 | PHP_MINFO_FUNCTION(wfio); 48 | 49 | PHP_FUNCTION(wfio_fopen8); 50 | PHP_FUNCTION(wfio_getcwd8); 51 | PHP_FUNCTION(wfio_path2utf8); 52 | PHP_FUNCTION(wfio_path_from_utf8); 53 | PHP_FUNCTION(wfio_path_combine); 54 | 55 | /* 56 | Declare any global variables you may need between the BEGIN 57 | and END macros here: 58 | 59 | ZEND_BEGIN_MODULE_GLOBALS(wfio) 60 | long global_value; 61 | char *global_string; 62 | ZEND_END_MODULE_GLOBALS(wfio) 63 | */ 64 | 65 | /* In every utility function you add that needs to use variables 66 | in php_wfio_globals, call TSRMLS_FETCH(); after declaring other 67 | variables used by that function, or better yet, pass in TSRMLS_CC 68 | after the last function argument and declare your utility function 69 | with TSRMLS_DC after the last declared argument. Always refer to 70 | the globals in your function as WFIO_G(variable). You are 71 | encouraged to rename these macros something shorter, see 72 | examples in any other php module directory. 73 | */ 74 | 75 | #ifdef ZTS 76 | #define WFIO_G(v) TSRMG(wfio_globals_id, zend_wfio_globals *, v) 77 | #else 78 | #define WFIO_G(v) (wfio_globals.v) 79 | #endif 80 | 81 | extern php_stream_wrapper php_stream_wfio_wrapper; 82 | 83 | #endif /* PHP_WFIO_H */ 84 | 85 | 86 | /* 87 | * Local variables: 88 | * tab-width: 4 89 | * c-basic-offset: 4 90 | * End: 91 | * vim600: noet sw=4 ts=4 fdm=marker 92 | * vim<600: noet sw=4 ts=4 93 | */ 94 | -------------------------------------------------------------------------------- /readdirw.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "php.h" 6 | #include "readdirw.h" 7 | /********************************************************************** 8 | * Implement dirent-style 9 | * opendirw 10 | * readdirw 11 | * rewinddirw 12 | * closedirw on Win32 13 | * 14 | * Functions will require Windows NT due to Unicode support. 15 | * 16 | * Windows 95/98/Me users don't require this, 17 | * because their OS doesn't have Unicode file support. 18 | **********************************************************************/ 19 | 20 | DIRW *opendirw(const wchar_t *dir) 21 | { 22 | DIRW *dp; 23 | wchar_t *filespec; 24 | HANDLE handle; 25 | int index; 26 | wchar_t resolved_path_buff[MAXPATHLEN]; 27 | 28 | wcsncpy(resolved_path_buff, dir, MAXPATHLEN); 29 | 30 | filespec = (wchar_t *)malloc(sizeof(wchar_t) * (wcslen(resolved_path_buff) + 2 + 1)); 31 | if (filespec == NULL) { 32 | return NULL; 33 | } 34 | wcscpy(filespec, resolved_path_buff); 35 | index = wcslen(filespec) - 1; 36 | if (index >= 0 && (filespec[index] == L'/' || (filespec[index] == L'\\'))) 37 | filespec[index] = L'\0'; 38 | wcscat(filespec, L"\\*"); 39 | 40 | dp = (DIRW *) malloc(sizeof(DIRW)); 41 | if (dp == NULL) { 42 | return NULL; 43 | } 44 | dp->offset = 0; 45 | dp->finished = 0; 46 | 47 | if ((handle = FindFirstFileW(filespec, &(dp->fileinfo))) == INVALID_HANDLE_VALUE) { 48 | DWORD err = GetLastError(); 49 | if (err == ERROR_NO_MORE_FILES || err == ERROR_FILE_NOT_FOUND) { 50 | dp->finished = 1; 51 | } else { 52 | free(dp); 53 | free(filespec); 54 | return NULL; 55 | } 56 | } 57 | dp->dir = wcsdup(resolved_path_buff); 58 | dp->handle = handle; 59 | free(filespec); 60 | 61 | return dp; 62 | } 63 | 64 | struct direntw *readdirw(DIRW *dp) 65 | { 66 | if (!dp || dp->finished) 67 | return NULL; 68 | 69 | if (dp->offset != 0) { 70 | if (FindNextFileW(dp->handle, &(dp->fileinfo)) == 0) { 71 | dp->finished = 1; 72 | return NULL; 73 | } 74 | } 75 | dp->offset++; 76 | 77 | wcsncpy(dp->dent.d_name, dp->fileinfo.cFileName, _MAX_FNAME+1); 78 | dp->dent.d_ino = 1; 79 | dp->dent.d_reclen = wcslen(dp->dent.d_name); 80 | dp->dent.d_off = dp->offset; 81 | 82 | return &(dp->dent); 83 | } 84 | 85 | int readdirw_r(DIRW *dp, struct direntw *entry, struct direntw **result) 86 | { 87 | if (!dp || dp->finished) { 88 | *result = NULL; 89 | return 0; 90 | } 91 | 92 | if (dp->offset != 0) { 93 | if (FindNextFileW(dp->handle, &(dp->fileinfo)) == 0) { 94 | dp->finished = 1; 95 | *result = NULL; 96 | return 0; 97 | } 98 | } 99 | dp->offset++; 100 | 101 | wcsncpy(dp->dent.d_name, dp->fileinfo.cFileName, _MAX_FNAME+1); 102 | dp->dent.d_ino = 1; 103 | dp->dent.d_reclen = wcslen(dp->dent.d_name); 104 | dp->dent.d_off = dp->offset; 105 | 106 | memcpy(entry, &dp->dent, sizeof(*entry)); 107 | 108 | *result = &dp->dent; 109 | 110 | return 0; 111 | } 112 | 113 | int closedirw(DIRW *dp) 114 | { 115 | if (!dp) 116 | return 0; 117 | /* It is valid to scan an empty directory but we have an invalid 118 | handle in this case (no first file found). */ 119 | if (dp->handle != INVALID_HANDLE_VALUE) { 120 | FindClose(dp->handle); 121 | } 122 | if (dp->dir) 123 | free(dp->dir); 124 | if (dp) 125 | free(dp); 126 | 127 | return 0; 128 | } 129 | 130 | int rewinddirw(DIRW *dp) 131 | { 132 | /* Re-set to the beginning */ 133 | wchar_t *filespec; 134 | HANDLE handle; 135 | int index; 136 | 137 | FindClose(dp->handle); 138 | 139 | dp->offset = 0; 140 | dp->finished = 0; 141 | 142 | filespec = (wchar_t *)malloc(sizeof(wchar_t) * (wcslen(dp->dir) + 2 + 1)); 143 | if (filespec == NULL) { 144 | return -1; 145 | } 146 | 147 | wcscpy(filespec, dp->dir); 148 | index = wcslen(filespec) - 1; 149 | if (index >= 0 && (filespec[index] == L'/' || (filespec[index] == L'\\'))) 150 | filespec[index] = L'\0'; 151 | wcscat(filespec, L"/*"); 152 | 153 | if ((handle = FindFirstFileW(filespec, &(dp->fileinfo))) == INVALID_HANDLE_VALUE) { 154 | dp->finished = 1; 155 | } 156 | 157 | dp->handle = handle; 158 | free(filespec); 159 | 160 | return 0; 161 | } 162 | -------------------------------------------------------------------------------- /readdirw.h: -------------------------------------------------------------------------------- 1 | #ifndef READDIRW_H 2 | #define READDIRW_H 3 | 4 | 5 | /* 6 | * Structures and types used to implement opendirw/readdirw/closedirw 7 | * on Windows NT. 8 | */ 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | /* struct dirent - same as Unix */ 19 | 20 | struct direntw { 21 | long d_ino; /* inode (always 1 in WIN32) */ 22 | off_t d_off; /* offset to this dirent */ 23 | unsigned short d_reclen; /* length of d_name */ 24 | wchar_t d_name[_MAX_FNAME + 1]; /* filename (null terminated) */ 25 | }; 26 | 27 | 28 | /* typedef DIR - not the same as Unix */ 29 | typedef struct { 30 | HANDLE handle; /* _findfirst/_findnext handle */ 31 | short offset; /* offset into directory */ 32 | short finished; /* 1 if there are not more files */ 33 | WIN32_FIND_DATAW fileinfo; /* from _findfirst/_findnext */ 34 | wchar_t *dir; /* the dir we are reading */ 35 | struct direntw dent; /* the dirent to return */ 36 | } DIRW; 37 | 38 | /* Function prototypes */ 39 | DIRW *opendirw(const wchar_t *); 40 | struct direntw *readdir8(DIRW *); 41 | int readdirw_r(DIRW *, struct direntw *, struct direntw **); 42 | int closedirw(DIRW *); 43 | int rewinddirw(DIRW *); 44 | 45 | #endif /* READDIRW_H */ 46 | -------------------------------------------------------------------------------- /tests/001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for wfio presence 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 20 | --EXPECT-- 21 | wfio extension is available 22 | -------------------------------------------------------------------------------- /tests/chdir.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Whether wfio follows php5's chdir. 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 62 | --EXPECT-- 63 | mkdir 1 64 | chdir 1 65 | touch 1 66 | wfio_fopen8 1 67 | fclose 1 68 | mkdir 1 69 | scandir array(2) { 70 | [0]=> 71 | string(1) "." 72 | [1]=> 73 | string(2) ".." 74 | } 75 | 76 | rmdir 1 77 | unlink 1 78 | chdir 1 79 | rmdir 1 80 | -------------------------------------------------------------------------------- /tests/compare_large_stat.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | wfio stat,normal stat "CWD/path_to_largefile.ext" int32 3 | --SKIPIF-- 4 | 9 | --FILE-- 10 | 23 | --EXPECT-- 24 | mtime 0 25 | size 0 26 | -------------------------------------------------------------------------------- /tests/compare_large_stat_int64.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | wfio stat,normal stat "CWD/path_to_largefile.ext" int64 3 | --SKIPIF-- 4 | 9 | --FILE-- 10 | 23 | --EXPECT-- 24 | mtime 0 25 | size 4294967296 26 | -------------------------------------------------------------------------------- /tests/compare_stat.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | wfio stat,normal stat 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 29 | --EXPECT-- 30 | file_put_contents 1 31 | mtime 0 32 | size 0 33 | unlink 1 34 | -------------------------------------------------------------------------------- /tests/compare_stat_fstat.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | wfio stat,fstat 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 31 | --EXPECT-- 32 | file_put_contents 1 33 | mtime 0 34 | size 0 35 | unlink 1 36 | -------------------------------------------------------------------------------- /tests/filefuncs.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | wfio file funcs like filemtime 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 57 | --EXPECT-- 58 | file_put_contents 1 59 | fileatime 0 60 | filectime 0 61 | filegroup 0 62 | fileinode 0 63 | filemtime 0 64 | fileowner 0 65 | fileperms 0 66 | filesize 0 67 | filetype 0 68 | unlink 1 69 | -------------------------------------------------------------------------------- /tests/fopen.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | wfio fopen,fclose,unlink 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 73 | --EXPECT-- 74 | wfio_fopen8 1 75 | fwrite 1 76 | ftell 5 5 77 | fseek 0,SEEK_SET 0 78 | ftell 0 0 79 | fseek 0,SEEK_END 0 80 | ftell 5 5 81 | fseek -1,SEEK_CUR 0 82 | ftell 4 4 83 | rewind 1 84 | ftell 0 0 85 | fclose 1 86 | fopen 1 87 | fread 12345 88 | fclose 1 89 | unlink 1 -------------------------------------------------------------------------------- /tests/mkdir.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | wfio mkdir,rmdir 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 30 | --EXPECT-- 31 | mkdir 1 32 | file_put_contents 6 33 | file_get_contents abc123 34 | unlink 1 35 | rmdir 1 36 | -------------------------------------------------------------------------------- /tests/mkdir_UTF8.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | wfio mkdir,rmdir utf-8 ver 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 115 | --EXPECT-- 116 | mkdir English 1 117 | tryscan English 1 118 | rmdir English 1 119 | 120 | mkdir Japanese 1 121 | tryscan Japanese 1 122 | rmdir Japanese 1 123 | 124 | mkdir ChineseSimplified 1 125 | tryscan ChineseSimplified 1 126 | rmdir ChineseSimplified 1 127 | 128 | mkdir French 1 129 | tryscan French 1 130 | rmdir French 1 131 | 132 | mkdir BrazilianPortuguese 1 133 | tryscan BrazilianPortuguese 1 134 | rmdir BrazilianPortuguese 1 135 | 136 | mkdir Russian 1 137 | tryscan Russian 1 138 | rmdir Russian 1 139 | -------------------------------------------------------------------------------- /tests/nonascii_cwd.phpt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenjiuno/php-wfio/d29f1073230a0bbb644ecd946668030a0c10f67f/tests/nonascii_cwd.phpt -------------------------------------------------------------------------------- /tests/scandir_crash_on_absent.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | wfio scandir crashes on absent 3 | --SKIPIF-- 4 | 5 | --FILE-- 6 | 20 | --EXPECT-- 21 | scandir1 22 | scandir2 23 | scandir3 24 | --------------------------------------------------------------------------------