spl_directory.c 79 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Copyright (c) The PHP Group |
  4. +----------------------------------------------------------------------+
  5. | This source file is subject to version 3.01 of the PHP license, |
  6. | that is bundled with this package in the file LICENSE, and is |
  7. | available through the world-wide-web at the following url: |
  8. | https://www.php.net/license/3_01.txt |
  9. | If you did not receive a copy of the PHP license and are unable to |
  10. | obtain it through the world-wide-web, please send a note to |
  11. | license@php.net so we can mail you a copy immediately. |
  12. +----------------------------------------------------------------------+
  13. | Author: Marcus Boerger <helly@php.net> |
  14. +----------------------------------------------------------------------+
  15. */
  16. #ifdef HAVE_CONFIG_H
  17. # include "config.h"
  18. #endif
  19. #include "php.h"
  20. #include "php_ini.h"
  21. #include "ext/standard/file.h"
  22. #include "ext/standard/php_filestat.h"
  23. #include "ext/standard/flock_compat.h"
  24. #include "ext/standard/scanf.h"
  25. #include "ext/standard/php_string.h"
  26. #include "zend_exceptions.h"
  27. #include "zend_interfaces.h"
  28. #include "php_spl.h"
  29. #include "spl_functions.h"
  30. #include "spl_engine.h"
  31. #include "spl_iterators.h"
  32. #include "spl_directory.h"
  33. #include "spl_directory_arginfo.h"
  34. #include "spl_exceptions.h"
  35. #define SPL_HAS_FLAG(flags, test_flag) ((flags & test_flag) ? 1 : 0)
  36. /* declare the class handlers */
  37. static zend_object_handlers spl_filesystem_object_handlers;
  38. /* includes handler to validate object state when retrieving methods */
  39. static zend_object_handlers spl_filesystem_object_check_handlers;
  40. /* decalre the class entry */
  41. PHPAPI zend_class_entry *spl_ce_SplFileInfo;
  42. PHPAPI zend_class_entry *spl_ce_DirectoryIterator;
  43. PHPAPI zend_class_entry *spl_ce_FilesystemIterator;
  44. PHPAPI zend_class_entry *spl_ce_RecursiveDirectoryIterator;
  45. PHPAPI zend_class_entry *spl_ce_GlobIterator;
  46. PHPAPI zend_class_entry *spl_ce_SplFileObject;
  47. PHPAPI zend_class_entry *spl_ce_SplTempFileObject;
  48. #define CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(spl_filesystem_object_pointer) \
  49. if (!(spl_filesystem_object_pointer)->u.file.stream) { \
  50. zend_throw_error(NULL, "Object not initialized"); \
  51. RETURN_THROWS(); \
  52. }
  53. #define CHECK_DIRECTORY_ITERATOR_IS_INITIALIZED(intern) \
  54. if (!(intern)->u.dir.dirp) { \
  55. zend_throw_error(NULL, "Object not initialized"); \
  56. RETURN_THROWS(); \
  57. }
  58. static void spl_filesystem_file_free_line(spl_filesystem_object *intern) /* {{{ */
  59. {
  60. if (intern->u.file.current_line) {
  61. efree(intern->u.file.current_line);
  62. intern->u.file.current_line = NULL;
  63. }
  64. if (!Z_ISUNDEF(intern->u.file.current_zval)) {
  65. zval_ptr_dtor(&intern->u.file.current_zval);
  66. ZVAL_UNDEF(&intern->u.file.current_zval);
  67. }
  68. } /* }}} */
  69. static void spl_filesystem_object_destroy_object(zend_object *object) /* {{{ */
  70. {
  71. spl_filesystem_object *intern = spl_filesystem_from_obj(object);
  72. zend_objects_destroy_object(object);
  73. switch(intern->type) {
  74. case SPL_FS_DIR:
  75. if (intern->u.dir.dirp) {
  76. php_stream_close(intern->u.dir.dirp);
  77. intern->u.dir.dirp = NULL;
  78. }
  79. break;
  80. case SPL_FS_FILE:
  81. if (intern->u.file.stream) {
  82. /*
  83. if (intern->u.file.zcontext) {
  84. zend_list_delref(Z_RESVAL_P(intern->zcontext));
  85. }
  86. */
  87. if (!intern->u.file.stream->is_persistent) {
  88. php_stream_close(intern->u.file.stream);
  89. } else {
  90. php_stream_pclose(intern->u.file.stream);
  91. }
  92. intern->u.file.stream = NULL;
  93. ZVAL_UNDEF(&intern->u.file.zresource);
  94. }
  95. break;
  96. default:
  97. break;
  98. }
  99. } /* }}} */
  100. static void spl_filesystem_object_free_storage(zend_object *object) /* {{{ */
  101. {
  102. spl_filesystem_object *intern = spl_filesystem_from_obj(object);
  103. if (intern->oth_handler && intern->oth_handler->dtor) {
  104. intern->oth_handler->dtor(intern);
  105. }
  106. zend_object_std_dtor(&intern->std);
  107. if (intern->path) {
  108. zend_string_release(intern->path);
  109. }
  110. if (intern->file_name) {
  111. zend_string_release(intern->file_name);
  112. }
  113. switch(intern->type) {
  114. case SPL_FS_INFO:
  115. break;
  116. case SPL_FS_DIR:
  117. if (intern->u.dir.sub_path) {
  118. zend_string_release(intern->u.dir.sub_path);
  119. }
  120. break;
  121. case SPL_FS_FILE:
  122. if (intern->u.file.open_mode) {
  123. zend_string_release(intern->u.file.open_mode);
  124. }
  125. if (intern->orig_path) {
  126. zend_string_release(intern->orig_path);
  127. }
  128. spl_filesystem_file_free_line(intern);
  129. break;
  130. }
  131. } /* }}} */
  132. /* {{{ spl_ce_dir_object_new */
  133. /* creates the object by
  134. - allocating memory
  135. - initializing the object members
  136. - storing the object
  137. - setting it's handlers
  138. called from
  139. - clone
  140. - new
  141. */
  142. static zend_object *spl_filesystem_object_new_ex(zend_class_entry *class_type)
  143. {
  144. spl_filesystem_object *intern;
  145. intern = emalloc(sizeof(spl_filesystem_object) + zend_object_properties_size(class_type));
  146. memset(intern, 0,
  147. MAX(XtOffsetOf(spl_filesystem_object, u.dir.entry),
  148. XtOffsetOf(spl_filesystem_object, u.file.escape) + sizeof(int)));
  149. /* intern->type = SPL_FS_INFO; done by set 0 */
  150. intern->file_class = spl_ce_SplFileObject;
  151. intern->info_class = spl_ce_SplFileInfo;
  152. zend_object_std_init(&intern->std, class_type);
  153. object_properties_init(&intern->std, class_type);
  154. intern->std.handlers = &spl_filesystem_object_handlers;
  155. return &intern->std;
  156. }
  157. /* }}} */
  158. /* {{{ spl_filesystem_object_new */
  159. /* See spl_filesystem_object_new_ex */
  160. static zend_object *spl_filesystem_object_new(zend_class_entry *class_type)
  161. {
  162. return spl_filesystem_object_new_ex(class_type);
  163. }
  164. /* }}} */
  165. /* {{{ spl_filesystem_object_new_check */
  166. static zend_object *spl_filesystem_object_new_check(zend_class_entry *class_type)
  167. {
  168. spl_filesystem_object *ret = spl_filesystem_from_obj(spl_filesystem_object_new_ex(class_type));
  169. ret->std.handlers = &spl_filesystem_object_check_handlers;
  170. return &ret->std;
  171. }
  172. /* }}} */
  173. PHPAPI char* spl_filesystem_object_get_path(spl_filesystem_object *intern, size_t *len) /* {{{ */
  174. {
  175. #ifdef HAVE_GLOB
  176. if (intern->type == SPL_FS_DIR) {
  177. if (php_stream_is(intern->u.dir.dirp ,&php_glob_stream_ops)) {
  178. return php_glob_stream_get_path(intern->u.dir.dirp, len);
  179. }
  180. }
  181. #endif
  182. if (len) {
  183. *len = intern->path ? ZSTR_LEN(intern->path) : 0;
  184. }
  185. return intern->path ? ZSTR_VAL(intern->path) : NULL;
  186. } /* }}} */
  187. static inline int spl_filesystem_object_get_file_name(spl_filesystem_object *intern) /* {{{ */
  188. {
  189. if (intern->file_name) {
  190. /* already known */
  191. return SUCCESS;
  192. }
  193. switch (intern->type) {
  194. case SPL_FS_INFO:
  195. case SPL_FS_FILE:
  196. zend_throw_error(NULL, "Object not initialized");
  197. return FAILURE;
  198. break;
  199. case SPL_FS_DIR:
  200. {
  201. size_t name_len;
  202. size_t path_len = 0;
  203. char *path;
  204. char slash = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_UNIXPATHS) ? '/' : DEFAULT_SLASH;
  205. path = spl_filesystem_object_get_path(intern, &path_len);
  206. /* if there is parent path, amend it, otherwise just use the given path as is */
  207. name_len = strlen(intern->u.dir.entry.d_name);
  208. if (path_len == 0) {
  209. intern->file_name = zend_string_init(intern->u.dir.entry.d_name, name_len, 0);
  210. } else {
  211. zend_string *file_name = zend_string_alloc(path_len + 1 + name_len, 0);
  212. memcpy(ZSTR_VAL(file_name), path, path_len);
  213. ZSTR_VAL(file_name)[path_len] = slash;
  214. memcpy(ZSTR_VAL(file_name) + path_len + 1, intern->u.dir.entry.d_name, name_len);
  215. ZSTR_VAL(file_name)[path_len + 1 + name_len] = 0;
  216. intern->file_name = file_name;
  217. }
  218. }
  219. break;
  220. }
  221. return SUCCESS;
  222. } /* }}} */
  223. static int spl_filesystem_dir_read(spl_filesystem_object *intern) /* {{{ */
  224. {
  225. if (intern->file_name) {
  226. /* invalidate */
  227. zend_string_release(intern->file_name);
  228. intern->file_name = NULL;
  229. }
  230. if (!intern->u.dir.dirp || !php_stream_readdir(intern->u.dir.dirp, &intern->u.dir.entry)) {
  231. intern->u.dir.entry.d_name[0] = '\0';
  232. return 0;
  233. } else {
  234. return 1;
  235. }
  236. }
  237. /* }}} */
  238. #define IS_SLASH_AT(zs, pos) (IS_SLASH(zs[pos]))
  239. static inline int spl_filesystem_is_dot(const char * d_name) /* {{{ */
  240. {
  241. return !strcmp(d_name, ".") || !strcmp(d_name, "..");
  242. }
  243. /* }}} */
  244. /* {{{ spl_filesystem_dir_open */
  245. /* open a directory resource
  246. * Can emit an E_WARNING as it reports errors from php_stream_opendir() */
  247. static void spl_filesystem_dir_open(spl_filesystem_object* intern, zend_string *path)
  248. {
  249. int skip_dots = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_SKIPDOTS);
  250. intern->type = SPL_FS_DIR;
  251. intern->u.dir.dirp = php_stream_opendir(ZSTR_VAL(path), REPORT_ERRORS, FG(default_context));
  252. if (ZSTR_LEN(path) > 1 && IS_SLASH_AT(ZSTR_VAL(path), ZSTR_LEN(path)-1)) {
  253. intern->path = zend_string_init(ZSTR_VAL(path), ZSTR_LEN(path)-1, 0);
  254. } else {
  255. intern->path = zend_string_copy(path);
  256. }
  257. intern->u.dir.index = 0;
  258. if (EG(exception) || intern->u.dir.dirp == NULL) {
  259. intern->u.dir.entry.d_name[0] = '\0';
  260. if (!EG(exception)) {
  261. /* open failed w/out notice (turned to exception due to EH_THROW) */
  262. zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
  263. "Failed to open directory \"%s\"", ZSTR_VAL(path));
  264. }
  265. } else {
  266. do {
  267. spl_filesystem_dir_read(intern);
  268. } while (skip_dots && spl_filesystem_is_dot(intern->u.dir.entry.d_name));
  269. }
  270. }
  271. /* }}} */
  272. /* Can generate E_WARNINGS as we report errors from stream initialized via
  273. * php_stream_open_wrapper_ex() */
  274. static zend_result spl_filesystem_file_open(spl_filesystem_object *intern, bool use_include_path) /* {{{ */
  275. {
  276. zval tmp;
  277. intern->type = SPL_FS_FILE;
  278. php_stat(intern->file_name, FS_IS_DIR, &tmp);
  279. if (Z_TYPE(tmp) == IS_TRUE) {
  280. zend_string_release(intern->u.file.open_mode);
  281. intern->u.file.open_mode = NULL;
  282. intern->file_name = NULL;
  283. zend_throw_exception_ex(spl_ce_LogicException, 0, "Cannot use SplFileObject with directories");
  284. return FAILURE;
  285. }
  286. intern->u.file.context = php_stream_context_from_zval(intern->u.file.zcontext, 0);
  287. intern->u.file.stream = php_stream_open_wrapper_ex(ZSTR_VAL(intern->file_name), ZSTR_VAL(intern->u.file.open_mode), (use_include_path ? USE_PATH : 0) | REPORT_ERRORS, NULL, intern->u.file.context);
  288. if (!ZSTR_LEN(intern->file_name) || !intern->u.file.stream) {
  289. if (!EG(exception)) {
  290. zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Cannot open file '%s'", ZSTR_VAL(intern->file_name));
  291. }
  292. zend_string_release(intern->u.file.open_mode);
  293. intern->u.file.open_mode = NULL;
  294. intern->file_name = NULL; /* until here it is not a copy */
  295. return FAILURE;
  296. }
  297. /*
  298. if (intern->u.file.zcontext) {
  299. //zend_list_addref(Z_RES_VAL(intern->u.file.zcontext));
  300. Z_ADDREF_P(intern->u.file.zcontext);
  301. }
  302. */
  303. if (ZSTR_LEN(intern->file_name) > 1 && IS_SLASH_AT(ZSTR_VAL(intern->file_name), ZSTR_LEN(intern->file_name)-1)) {
  304. intern->file_name = zend_string_init(ZSTR_VAL(intern->file_name), ZSTR_LEN(intern->file_name)-1, 0);
  305. } else {
  306. intern->file_name = zend_string_copy(intern->file_name);
  307. }
  308. intern->orig_path = zend_string_init(intern->u.file.stream->orig_path, strlen(intern->u.file.stream->orig_path), 0);
  309. /* avoid reference counting in debug mode, thus do it manually */
  310. ZVAL_RES(&intern->u.file.zresource, intern->u.file.stream->res);
  311. /*!!! TODO: maybe bug?
  312. Z_SET_REFCOUNT(intern->u.file.zresource, 1);
  313. */
  314. intern->u.file.delimiter = ',';
  315. intern->u.file.enclosure = '"';
  316. intern->u.file.escape = (unsigned char) '\\';
  317. intern->u.file.func_getCurr = zend_hash_str_find_ptr(&intern->std.ce->function_table, "getcurrentline", sizeof("getcurrentline") - 1);
  318. return SUCCESS;
  319. } /* }}} */
  320. /* {{{ spl_filesystem_object_clone */
  321. /* Local zend_object creation (on stack)
  322. Load the 'other' object
  323. Create a new empty object (See spl_filesystem_object_new_ex)
  324. Open the directory
  325. Clone other members (properties)
  326. */
  327. static zend_object *spl_filesystem_object_clone(zend_object *old_object)
  328. {
  329. zend_object *new_object;
  330. spl_filesystem_object *intern;
  331. spl_filesystem_object *source;
  332. int index, skip_dots;
  333. source = spl_filesystem_from_obj(old_object);
  334. new_object = spl_filesystem_object_new_ex(old_object->ce);
  335. intern = spl_filesystem_from_obj(new_object);
  336. intern->flags = source->flags;
  337. switch (source->type) {
  338. case SPL_FS_INFO:
  339. if (source->path != NULL) {
  340. intern->path = zend_string_copy(source->path);
  341. }
  342. if (source->file_name != NULL) {
  343. intern->file_name = zend_string_copy(source->file_name);
  344. }
  345. break;
  346. case SPL_FS_DIR:
  347. spl_filesystem_dir_open(intern, source->path);
  348. /* read until we hit the position in which we were before */
  349. skip_dots = SPL_HAS_FLAG(source->flags, SPL_FILE_DIR_SKIPDOTS);
  350. for(index = 0; index < source->u.dir.index; ++index) {
  351. do {
  352. spl_filesystem_dir_read(intern);
  353. } while (skip_dots && spl_filesystem_is_dot(intern->u.dir.entry.d_name));
  354. }
  355. intern->u.dir.index = index;
  356. break;
  357. case SPL_FS_FILE:
  358. ZEND_UNREACHABLE();
  359. }
  360. intern->file_class = source->file_class;
  361. intern->info_class = source->info_class;
  362. intern->oth = source->oth;
  363. intern->oth_handler = source->oth_handler;
  364. zend_objects_clone_members(new_object, old_object);
  365. if (intern->oth_handler && intern->oth_handler->clone) {
  366. intern->oth_handler->clone(source, intern);
  367. }
  368. return new_object;
  369. }
  370. /* }}} */
  371. static void spl_filesystem_info_set_filename(spl_filesystem_object *intern, zend_string *path) /* {{{ */
  372. {
  373. size_t path_len;
  374. if (intern->file_name) {
  375. zend_string_release(intern->file_name);
  376. }
  377. path_len = ZSTR_LEN(path);
  378. if (path_len > 1 && IS_SLASH_AT(ZSTR_VAL(path), path_len-1)) {
  379. path_len--;
  380. intern->file_name = zend_string_init(ZSTR_VAL(path), path_len, 0);
  381. } else {
  382. intern->file_name = zend_string_copy(path);
  383. }
  384. while (path_len > 1 && !IS_SLASH_AT(ZSTR_VAL(path), path_len-1)) {
  385. path_len--;
  386. }
  387. if (path_len) {
  388. path_len--;
  389. }
  390. if (intern->path) {
  391. zend_string_release(intern->path);
  392. }
  393. intern->path = zend_string_init(ZSTR_VAL(path), path_len, 0);
  394. } /* }}} */
  395. static spl_filesystem_object *spl_filesystem_object_create_info(spl_filesystem_object *source, zend_string *file_path, zend_class_entry *ce, zval *return_value) /* {{{ */
  396. {
  397. spl_filesystem_object *intern;
  398. zval arg1;
  399. if (!file_path || !ZSTR_LEN(file_path)) {
  400. #ifdef PHP_WIN32
  401. zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Cannot create SplFileInfo for empty path");
  402. #endif
  403. return NULL;
  404. }
  405. ce = ce ? ce : source->info_class;
  406. intern = spl_filesystem_from_obj(spl_filesystem_object_new_ex(ce));
  407. RETVAL_OBJ(&intern->std);
  408. if (ce->constructor->common.scope != spl_ce_SplFileInfo) {
  409. ZVAL_STR_COPY(&arg1, file_path);
  410. zend_call_method_with_1_params(Z_OBJ_P(return_value), ce, &ce->constructor, "__construct", NULL, &arg1);
  411. zval_ptr_dtor(&arg1);
  412. } else {
  413. spl_filesystem_info_set_filename(intern, file_path);
  414. }
  415. return intern;
  416. } /* }}} */
  417. static spl_filesystem_object *spl_filesystem_object_create_type(int num_args, spl_filesystem_object *source, int type, zend_class_entry *ce, zval *return_value) /* {{{ */
  418. {
  419. spl_filesystem_object *intern;
  420. bool use_include_path = 0;
  421. zval arg1, arg2;
  422. zend_error_handling error_handling;
  423. switch (source->type) {
  424. case SPL_FS_INFO:
  425. case SPL_FS_FILE:
  426. break;
  427. case SPL_FS_DIR:
  428. if (!source->u.dir.entry.d_name[0]) {
  429. zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Could not open file");
  430. return NULL;
  431. }
  432. }
  433. switch (type) {
  434. case SPL_FS_INFO:
  435. ce = ce ? ce : source->info_class;
  436. intern = spl_filesystem_from_obj(spl_filesystem_object_new_ex(ce));
  437. RETVAL_OBJ(&intern->std);
  438. if (spl_filesystem_object_get_file_name(source) != SUCCESS) {
  439. return NULL;
  440. }
  441. if (ce->constructor->common.scope != spl_ce_SplFileInfo) {
  442. ZVAL_STR_COPY(&arg1, source->file_name);
  443. zend_call_method_with_1_params(Z_OBJ_P(return_value), ce, &ce->constructor, "__construct", NULL, &arg1);
  444. zval_ptr_dtor(&arg1);
  445. } else {
  446. char *path;
  447. size_t path_len;
  448. intern->file_name = zend_string_copy(source->file_name);
  449. path = spl_filesystem_object_get_path(source, &path_len);
  450. if (source->path && ZSTR_VAL(source->path) == path) {
  451. intern->path = zend_string_copy(source->path);
  452. } else {
  453. intern->path = zend_string_init(path, path_len, 0);
  454. }
  455. }
  456. break;
  457. case SPL_FS_FILE:
  458. {
  459. ce = ce ? ce : source->file_class;
  460. zend_string *open_mode = ZSTR_CHAR('r');
  461. zval *resource = NULL;
  462. if (zend_parse_parameters(num_args, "|Sbr!",
  463. &open_mode, &use_include_path, &resource) == FAILURE
  464. ) {
  465. return NULL;
  466. }
  467. intern = spl_filesystem_from_obj(spl_filesystem_object_new_ex(ce));
  468. RETVAL_OBJ(&intern->std);
  469. if (spl_filesystem_object_get_file_name(source) != SUCCESS) {
  470. return NULL;
  471. }
  472. if (ce->constructor->common.scope != spl_ce_SplFileObject) {
  473. ZVAL_STR_COPY(&arg1, source->file_name);
  474. ZVAL_STR_COPY(&arg2, open_mode);
  475. zend_call_method_with_2_params(Z_OBJ_P(return_value), ce, &ce->constructor, "__construct", NULL, &arg1, &arg2);
  476. zval_ptr_dtor(&arg1);
  477. zval_ptr_dtor(&arg2);
  478. } else {
  479. char *path;
  480. size_t path_len;
  481. intern->file_name = source->file_name;
  482. path = spl_filesystem_object_get_path(source, &path_len);
  483. if (source->path && ZSTR_VAL(source->path) == path) {
  484. intern->path = zend_string_copy(source->path);
  485. } else {
  486. intern->path = zend_string_init(path, path_len, 0);
  487. }
  488. intern->u.file.open_mode = zend_string_copy(open_mode);
  489. intern->u.file.zcontext = resource;
  490. /* spl_filesystem_file_open() can generate E_WARNINGs which we want to promote to exceptions */
  491. zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling);
  492. if (spl_filesystem_file_open(intern, use_include_path) == FAILURE) {
  493. zend_restore_error_handling(&error_handling);
  494. zval_ptr_dtor(return_value);
  495. ZVAL_NULL(return_value);
  496. return NULL;
  497. }
  498. zend_restore_error_handling(&error_handling);
  499. }
  500. break;
  501. }
  502. case SPL_FS_DIR:
  503. zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Operation not supported");
  504. return NULL;
  505. }
  506. return NULL;
  507. } /* }}} */
  508. static int spl_filesystem_is_invalid_or_dot(const char * d_name) /* {{{ */
  509. {
  510. return d_name[0] == '\0' || spl_filesystem_is_dot(d_name);
  511. }
  512. /* }}} */
  513. static zend_string *spl_filesystem_object_get_pathname(spl_filesystem_object *intern) { /* {{{ */
  514. switch (intern->type) {
  515. case SPL_FS_INFO:
  516. case SPL_FS_FILE:
  517. return intern->file_name;
  518. case SPL_FS_DIR:
  519. if (intern->u.dir.entry.d_name[0]) {
  520. spl_filesystem_object_get_file_name(intern);
  521. return intern->file_name;
  522. }
  523. }
  524. return NULL;
  525. }
  526. /* }}} */
  527. static inline HashTable *spl_filesystem_object_get_debug_info(zend_object *object) /* {{{ */
  528. {
  529. spl_filesystem_object *intern = spl_filesystem_from_obj(object);
  530. zval tmp;
  531. HashTable *rv;
  532. zend_string *pnstr;
  533. zend_string *path;
  534. char stmp[2];
  535. if (!intern->std.properties) {
  536. rebuild_object_properties(&intern->std);
  537. }
  538. rv = zend_array_dup(intern->std.properties);
  539. pnstr = spl_gen_private_prop_name(spl_ce_SplFileInfo, "pathName", sizeof("pathName")-1);
  540. path = spl_filesystem_object_get_pathname(intern);
  541. if (path) {
  542. ZVAL_STR_COPY(&tmp, path);
  543. } else {
  544. ZVAL_EMPTY_STRING(&tmp);
  545. }
  546. zend_symtable_update(rv, pnstr, &tmp);
  547. zend_string_release_ex(pnstr, 0);
  548. if (intern->file_name) {
  549. size_t path_len;
  550. pnstr = spl_gen_private_prop_name(spl_ce_SplFileInfo, "fileName", sizeof("fileName")-1);
  551. spl_filesystem_object_get_path(intern, &path_len);
  552. if (path_len && path_len < ZSTR_LEN(intern->file_name)) {
  553. ZVAL_STRINGL(&tmp, ZSTR_VAL(intern->file_name) + path_len + 1, ZSTR_LEN(intern->file_name) - (path_len + 1));
  554. } else {
  555. ZVAL_STR_COPY(&tmp, intern->file_name);
  556. }
  557. zend_symtable_update(rv, pnstr, &tmp);
  558. zend_string_release_ex(pnstr, 0);
  559. }
  560. if (intern->type == SPL_FS_DIR) {
  561. #ifdef HAVE_GLOB
  562. pnstr = spl_gen_private_prop_name(spl_ce_DirectoryIterator, "glob", sizeof("glob")-1);
  563. if (php_stream_is(intern->u.dir.dirp ,&php_glob_stream_ops)) {
  564. ZVAL_STR_COPY(&tmp, intern->path);
  565. } else {
  566. ZVAL_FALSE(&tmp);
  567. }
  568. zend_symtable_update(rv, pnstr, &tmp);
  569. zend_string_release_ex(pnstr, 0);
  570. #endif
  571. pnstr = spl_gen_private_prop_name(spl_ce_RecursiveDirectoryIterator, "subPathName", sizeof("subPathName")-1);
  572. if (intern->u.dir.sub_path) {
  573. ZVAL_STR_COPY(&tmp, intern->u.dir.sub_path);
  574. } else {
  575. ZVAL_EMPTY_STRING(&tmp);
  576. }
  577. zend_symtable_update(rv, pnstr, &tmp);
  578. zend_string_release_ex(pnstr, 0);
  579. }
  580. if (intern->type == SPL_FS_FILE) {
  581. pnstr = spl_gen_private_prop_name(spl_ce_SplFileObject, "openMode", sizeof("openMode")-1);
  582. ZVAL_STR_COPY(&tmp, intern->u.file.open_mode);
  583. zend_symtable_update(rv, pnstr, &tmp);
  584. zend_string_release_ex(pnstr, 0);
  585. stmp[1] = '\0';
  586. stmp[0] = intern->u.file.delimiter;
  587. pnstr = spl_gen_private_prop_name(spl_ce_SplFileObject, "delimiter", sizeof("delimiter")-1);
  588. ZVAL_STRINGL(&tmp, stmp, 1);
  589. zend_symtable_update(rv, pnstr, &tmp);
  590. zend_string_release_ex(pnstr, 0);
  591. stmp[0] = intern->u.file.enclosure;
  592. pnstr = spl_gen_private_prop_name(spl_ce_SplFileObject, "enclosure", sizeof("enclosure")-1);
  593. ZVAL_STRINGL(&tmp, stmp, 1);
  594. zend_symtable_update(rv, pnstr, &tmp);
  595. zend_string_release_ex(pnstr, 0);
  596. }
  597. return rv;
  598. }
  599. /* }}} */
  600. zend_function *spl_filesystem_object_get_method_check(zend_object **object, zend_string *method, const zval *key) /* {{{ */
  601. {
  602. spl_filesystem_object *fsobj = spl_filesystem_from_obj(*object);
  603. if (fsobj->u.dir.dirp == NULL && fsobj->orig_path == NULL) {
  604. zend_function *func;
  605. zend_string *tmp = zend_string_init("_bad_state_ex", sizeof("_bad_state_ex") - 1, 0);
  606. func = zend_std_get_method(object, tmp, NULL);
  607. zend_string_release_ex(tmp, 0);
  608. return func;
  609. }
  610. return zend_std_get_method(object, method, key);
  611. }
  612. /* }}} */
  613. #define DIT_CTOR_FLAGS 0x00000001
  614. #define DIT_CTOR_GLOB 0x00000002
  615. void spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAMETERS, zend_long ctor_flags) /* {{{ */
  616. {
  617. spl_filesystem_object *intern;
  618. zend_string *path;
  619. int parsed;
  620. zend_long flags;
  621. zend_error_handling error_handling;
  622. if (SPL_HAS_FLAG(ctor_flags, DIT_CTOR_FLAGS)) {
  623. flags = SPL_FILE_DIR_KEY_AS_PATHNAME|SPL_FILE_DIR_CURRENT_AS_FILEINFO;
  624. parsed = zend_parse_parameters(ZEND_NUM_ARGS(), "P|l", &path, &flags);
  625. } else {
  626. flags = SPL_FILE_DIR_KEY_AS_PATHNAME|SPL_FILE_DIR_CURRENT_AS_SELF;
  627. parsed = zend_parse_parameters(ZEND_NUM_ARGS(), "P", &path);
  628. }
  629. if (SPL_HAS_FLAG(ctor_flags, SPL_FILE_DIR_SKIPDOTS)) {
  630. flags |= SPL_FILE_DIR_SKIPDOTS;
  631. }
  632. if (SPL_HAS_FLAG(ctor_flags, SPL_FILE_DIR_UNIXPATHS)) {
  633. flags |= SPL_FILE_DIR_UNIXPATHS;
  634. }
  635. if (parsed == FAILURE) {
  636. RETURN_THROWS();
  637. }
  638. if (ZSTR_LEN(path) == 0) {
  639. zend_argument_value_error(1, "cannot be empty");
  640. RETURN_THROWS();
  641. }
  642. intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  643. if (intern->path) {
  644. /* object is already initialized */
  645. zend_throw_error(NULL, "Directory object is already initialized");
  646. RETURN_THROWS();
  647. }
  648. intern->flags = flags;
  649. /* spl_filesystem_dir_open() may emit an E_WARNING */
  650. zend_replace_error_handling(EH_THROW, spl_ce_UnexpectedValueException, &error_handling);
  651. #ifdef HAVE_GLOB
  652. if (SPL_HAS_FLAG(ctor_flags, DIT_CTOR_GLOB) && memcmp(ZSTR_VAL(path), "glob://", sizeof("glob://")-1) != 0) {
  653. path = zend_strpprintf(0, "glob://%s", ZSTR_VAL(path));
  654. spl_filesystem_dir_open(intern, path);
  655. zend_string_release(path);
  656. } else
  657. #endif
  658. {
  659. spl_filesystem_dir_open(intern, path);
  660. }
  661. zend_restore_error_handling(&error_handling);
  662. intern->u.dir.is_recursive = instanceof_function(intern->std.ce, spl_ce_RecursiveDirectoryIterator) ? 1 : 0;
  663. }
  664. /* }}} */
  665. /* {{{ Cronstructs a new dir iterator from a path. */
  666. PHP_METHOD(DirectoryIterator, __construct)
  667. {
  668. spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
  669. }
  670. /* }}} */
  671. /* {{{ Rewind dir back to the start */
  672. PHP_METHOD(DirectoryIterator, rewind)
  673. {
  674. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  675. if (zend_parse_parameters_none() == FAILURE) {
  676. RETURN_THROWS();
  677. }
  678. CHECK_DIRECTORY_ITERATOR_IS_INITIALIZED(intern);
  679. intern->u.dir.index = 0;
  680. php_stream_rewinddir(intern->u.dir.dirp);
  681. spl_filesystem_dir_read(intern);
  682. }
  683. /* }}} */
  684. /* {{{ Return current dir entry */
  685. PHP_METHOD(DirectoryIterator, key)
  686. {
  687. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  688. if (zend_parse_parameters_none() == FAILURE) {
  689. RETURN_THROWS();
  690. }
  691. CHECK_DIRECTORY_ITERATOR_IS_INITIALIZED(intern);
  692. RETURN_LONG(intern->u.dir.index);
  693. }
  694. /* }}} */
  695. /* {{{ Return this (needed for Iterator interface) */
  696. PHP_METHOD(DirectoryIterator, current)
  697. {
  698. if (zend_parse_parameters_none() == FAILURE) {
  699. RETURN_THROWS();
  700. }
  701. CHECK_DIRECTORY_ITERATOR_IS_INITIALIZED(Z_SPLFILESYSTEM_P(ZEND_THIS));
  702. RETURN_OBJ_COPY(Z_OBJ_P(ZEND_THIS));
  703. }
  704. /* }}} */
  705. /* {{{ Move to next entry */
  706. PHP_METHOD(DirectoryIterator, next)
  707. {
  708. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  709. int skip_dots = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_SKIPDOTS);
  710. if (zend_parse_parameters_none() == FAILURE) {
  711. RETURN_THROWS();
  712. }
  713. CHECK_DIRECTORY_ITERATOR_IS_INITIALIZED(intern);
  714. intern->u.dir.index++;
  715. do {
  716. spl_filesystem_dir_read(intern);
  717. } while (skip_dots && spl_filesystem_is_dot(intern->u.dir.entry.d_name));
  718. if (intern->file_name) {
  719. zend_string_release(intern->file_name);
  720. intern->file_name = NULL;
  721. }
  722. }
  723. /* }}} */
  724. /* {{{ Seek to the given position */
  725. PHP_METHOD(DirectoryIterator, seek)
  726. {
  727. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  728. zval retval;
  729. zend_long pos;
  730. if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &pos) == FAILURE) {
  731. RETURN_THROWS();
  732. }
  733. CHECK_DIRECTORY_ITERATOR_IS_INITIALIZED(intern);
  734. if (intern->u.dir.index > pos) {
  735. /* we first rewind */
  736. zend_call_method_with_0_params(Z_OBJ_P(ZEND_THIS), Z_OBJCE_P(ZEND_THIS), &intern->u.dir.func_rewind, "rewind", NULL);
  737. }
  738. while (intern->u.dir.index < pos) {
  739. int valid = 0;
  740. zend_call_method_with_0_params(Z_OBJ_P(ZEND_THIS), Z_OBJCE_P(ZEND_THIS), &intern->u.dir.func_valid, "valid", &retval);
  741. valid = zend_is_true(&retval);
  742. zval_ptr_dtor(&retval);
  743. if (!valid) {
  744. zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0, "Seek position " ZEND_LONG_FMT " is out of range", pos);
  745. RETURN_THROWS();
  746. }
  747. zend_call_method_with_0_params(Z_OBJ_P(ZEND_THIS), Z_OBJCE_P(ZEND_THIS), &intern->u.dir.func_next, "next", NULL);
  748. }
  749. } /* }}} */
  750. /* {{{ Check whether dir contains more entries */
  751. PHP_METHOD(DirectoryIterator, valid)
  752. {
  753. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  754. if (zend_parse_parameters_none() == FAILURE) {
  755. RETURN_THROWS();
  756. }
  757. CHECK_DIRECTORY_ITERATOR_IS_INITIALIZED(intern);
  758. RETURN_BOOL(intern->u.dir.entry.d_name[0] != '\0');
  759. }
  760. /* }}} */
  761. /* {{{ Return the path */
  762. PHP_METHOD(SplFileInfo, getPath)
  763. {
  764. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  765. char *path;
  766. size_t path_len;
  767. if (zend_parse_parameters_none() == FAILURE) {
  768. RETURN_THROWS();
  769. }
  770. path = spl_filesystem_object_get_path(intern, &path_len);
  771. if (path) {
  772. RETURN_STRINGL(path, path_len);
  773. } else {
  774. RETURN_EMPTY_STRING();
  775. }
  776. }
  777. /* }}} */
  778. /* {{{ Return filename only */
  779. PHP_METHOD(SplFileInfo, getFilename)
  780. {
  781. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  782. size_t path_len;
  783. if (zend_parse_parameters_none() == FAILURE) {
  784. RETURN_THROWS();
  785. }
  786. if (!intern->file_name) {
  787. zend_throw_error(NULL, "Object not initialized");
  788. RETURN_THROWS();
  789. }
  790. spl_filesystem_object_get_path(intern, &path_len);
  791. if (path_len && path_len < ZSTR_LEN(intern->file_name)) {
  792. RETURN_STRINGL(ZSTR_VAL(intern->file_name) + path_len + 1, ZSTR_LEN(intern->file_name) - (path_len + 1));
  793. } else {
  794. RETURN_STR_COPY(intern->file_name);
  795. }
  796. }
  797. /* }}} */
  798. /* {{{ Return filename of current dir entry */
  799. PHP_METHOD(DirectoryIterator, getFilename)
  800. {
  801. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  802. if (zend_parse_parameters_none() == FAILURE) {
  803. RETURN_THROWS();
  804. }
  805. CHECK_DIRECTORY_ITERATOR_IS_INITIALIZED(intern);
  806. RETURN_STRING(intern->u.dir.entry.d_name);
  807. }
  808. /* }}} */
  809. /* {{{ Returns file extension component of path */
  810. PHP_METHOD(SplFileInfo, getExtension)
  811. {
  812. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  813. char *fname = NULL;
  814. const char *p;
  815. size_t flen;
  816. size_t path_len;
  817. size_t idx;
  818. zend_string *ret;
  819. if (zend_parse_parameters_none() == FAILURE) {
  820. RETURN_THROWS();
  821. }
  822. if (!intern->file_name) {
  823. zend_throw_error(NULL, "Object not initialized");
  824. RETURN_THROWS();
  825. }
  826. spl_filesystem_object_get_path(intern, &path_len);
  827. if (path_len && path_len < ZSTR_LEN(intern->file_name)) {
  828. fname = ZSTR_VAL(intern->file_name) + path_len + 1;
  829. flen = ZSTR_LEN(intern->file_name) - (path_len + 1);
  830. } else {
  831. fname = ZSTR_VAL(intern->file_name);
  832. flen = ZSTR_LEN(intern->file_name);
  833. }
  834. ret = php_basename(fname, flen, NULL, 0);
  835. p = zend_memrchr(ZSTR_VAL(ret), '.', ZSTR_LEN(ret));
  836. if (p) {
  837. idx = p - ZSTR_VAL(ret);
  838. RETVAL_STRINGL(ZSTR_VAL(ret) + idx + 1, ZSTR_LEN(ret) - idx - 1);
  839. zend_string_release_ex(ret, 0);
  840. return;
  841. } else {
  842. zend_string_release_ex(ret, 0);
  843. RETURN_EMPTY_STRING();
  844. }
  845. }
  846. /* }}}*/
  847. /* {{{ Returns the file extension component of path */
  848. PHP_METHOD(DirectoryIterator, getExtension)
  849. {
  850. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  851. const char *p;
  852. size_t idx;
  853. zend_string *fname;
  854. if (zend_parse_parameters_none() == FAILURE) {
  855. RETURN_THROWS();
  856. }
  857. CHECK_DIRECTORY_ITERATOR_IS_INITIALIZED(intern);
  858. fname = php_basename(intern->u.dir.entry.d_name, strlen(intern->u.dir.entry.d_name), NULL, 0);
  859. p = zend_memrchr(ZSTR_VAL(fname), '.', ZSTR_LEN(fname));
  860. if (p) {
  861. idx = p - ZSTR_VAL(fname);
  862. RETVAL_STRINGL(ZSTR_VAL(fname) + idx + 1, ZSTR_LEN(fname) - idx - 1);
  863. zend_string_release_ex(fname, 0);
  864. } else {
  865. zend_string_release_ex(fname, 0);
  866. RETURN_EMPTY_STRING();
  867. }
  868. }
  869. /* }}} */
  870. /* {{{ Returns filename component of path */
  871. PHP_METHOD(SplFileInfo, getBasename)
  872. {
  873. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  874. char *fname, *suffix = 0;
  875. size_t flen;
  876. size_t slen = 0, path_len;
  877. if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s", &suffix, &slen) == FAILURE) {
  878. RETURN_THROWS();
  879. }
  880. if (!intern->file_name) {
  881. zend_throw_error(NULL, "Object not initialized");
  882. RETURN_THROWS();
  883. }
  884. spl_filesystem_object_get_path(intern, &path_len);
  885. if (path_len && path_len < ZSTR_LEN(intern->file_name)) {
  886. fname = ZSTR_VAL(intern->file_name) + path_len + 1;
  887. flen = ZSTR_LEN(intern->file_name) - (path_len + 1);
  888. } else {
  889. fname = ZSTR_VAL(intern->file_name);
  890. flen = ZSTR_LEN(intern->file_name);
  891. }
  892. RETURN_STR(php_basename(fname, flen, suffix, slen));
  893. }
  894. /* }}}*/
  895. /* {{{ Returns filename component of current dir entry */
  896. PHP_METHOD(DirectoryIterator, getBasename)
  897. {
  898. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  899. char *suffix = 0;
  900. size_t slen = 0;
  901. zend_string *fname;
  902. if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s", &suffix, &slen) == FAILURE) {
  903. RETURN_THROWS();
  904. }
  905. CHECK_DIRECTORY_ITERATOR_IS_INITIALIZED(intern);
  906. fname = php_basename(intern->u.dir.entry.d_name, strlen(intern->u.dir.entry.d_name), suffix, slen);
  907. RETVAL_STR(fname);
  908. }
  909. /* }}} */
  910. /* {{{ Return path and filename */
  911. PHP_METHOD(SplFileInfo, getPathname)
  912. {
  913. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  914. zend_string *path;
  915. if (zend_parse_parameters_none() == FAILURE) {
  916. RETURN_THROWS();
  917. }
  918. path = spl_filesystem_object_get_pathname(intern);
  919. if (path) {
  920. RETURN_STR_COPY(path);
  921. } else {
  922. RETURN_EMPTY_STRING();
  923. }
  924. }
  925. /* }}} */
  926. /* {{{ Return getPathname() or getFilename() depending on flags */
  927. PHP_METHOD(FilesystemIterator, key)
  928. {
  929. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  930. if (zend_parse_parameters_none() == FAILURE) {
  931. RETURN_THROWS();
  932. }
  933. if (SPL_FILE_DIR_KEY(intern, SPL_FILE_DIR_KEY_AS_FILENAME)) {
  934. RETURN_STRING(intern->u.dir.entry.d_name);
  935. } else {
  936. if (spl_filesystem_object_get_file_name(intern) != SUCCESS) {
  937. RETURN_THROWS();
  938. }
  939. RETURN_STR_COPY(intern->file_name);
  940. }
  941. }
  942. /* }}} */
  943. /* {{{ Return getFilename(), getFileInfo() or $this depending on flags */
  944. PHP_METHOD(FilesystemIterator, current)
  945. {
  946. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  947. if (zend_parse_parameters_none() == FAILURE) {
  948. RETURN_THROWS();
  949. }
  950. if (SPL_FILE_DIR_CURRENT(intern, SPL_FILE_DIR_CURRENT_AS_PATHNAME)) {
  951. if (spl_filesystem_object_get_file_name(intern) != SUCCESS) {
  952. RETURN_THROWS();
  953. }
  954. RETURN_STR_COPY(intern->file_name);
  955. } else if (SPL_FILE_DIR_CURRENT(intern, SPL_FILE_DIR_CURRENT_AS_FILEINFO)) {
  956. if (spl_filesystem_object_get_file_name(intern) != SUCCESS) {
  957. RETURN_THROWS();
  958. }
  959. spl_filesystem_object_create_type(0, intern, SPL_FS_INFO, NULL, return_value);
  960. } else {
  961. RETURN_OBJ_COPY(Z_OBJ_P(ZEND_THIS));
  962. }
  963. }
  964. /* }}} */
  965. /* {{{ Returns true if current entry is '.' or '..' */
  966. PHP_METHOD(DirectoryIterator, isDot)
  967. {
  968. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  969. if (zend_parse_parameters_none() == FAILURE) {
  970. RETURN_THROWS();
  971. }
  972. CHECK_DIRECTORY_ITERATOR_IS_INITIALIZED(intern);
  973. RETURN_BOOL(spl_filesystem_is_dot(intern->u.dir.entry.d_name));
  974. }
  975. /* }}} */
  976. /* {{{ Cronstructs a new SplFileInfo from a path. */
  977. /* When the constructor gets called the object is already created
  978. by the engine, so we must only call 'additional' initializations.
  979. */
  980. PHP_METHOD(SplFileInfo, __construct)
  981. {
  982. spl_filesystem_object *intern;
  983. zend_string *path;
  984. if (zend_parse_parameters(ZEND_NUM_ARGS(), "P", &path) == FAILURE) {
  985. RETURN_THROWS();
  986. }
  987. intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  988. spl_filesystem_info_set_filename(intern, path);
  989. /* intern->type = SPL_FS_INFO; already set */
  990. }
  991. /* }}} */
  992. /* {{{ FileInfoFunction */
  993. #define FileInfoFunction(func_name, func_num) \
  994. PHP_METHOD(SplFileInfo, func_name) \
  995. { \
  996. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS); \
  997. zend_error_handling error_handling; \
  998. if (zend_parse_parameters_none() == FAILURE) { \
  999. RETURN_THROWS(); \
  1000. } \
  1001. if (spl_filesystem_object_get_file_name(intern) != SUCCESS) { \
  1002. RETURN_THROWS(); \
  1003. } \
  1004. zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling);\
  1005. php_stat(intern->file_name, func_num, return_value); \
  1006. zend_restore_error_handling(&error_handling); \
  1007. }
  1008. /* }}} */
  1009. /* {{{ Get file permissions */
  1010. FileInfoFunction(getPerms, FS_PERMS)
  1011. /* }}} */
  1012. /* {{{ Get file inode */
  1013. FileInfoFunction(getInode, FS_INODE)
  1014. /* }}} */
  1015. /* {{{ Get file size */
  1016. FileInfoFunction(getSize, FS_SIZE)
  1017. /* }}} */
  1018. /* {{{ Get file owner */
  1019. FileInfoFunction(getOwner, FS_OWNER)
  1020. /* }}} */
  1021. /* {{{ Get file group */
  1022. FileInfoFunction(getGroup, FS_GROUP)
  1023. /* }}} */
  1024. /* {{{ Get last access time of file */
  1025. FileInfoFunction(getATime, FS_ATIME)
  1026. /* }}} */
  1027. /* {{{ Get last modification time of file */
  1028. FileInfoFunction(getMTime, FS_MTIME)
  1029. /* }}} */
  1030. /* {{{ Get inode modification time of file */
  1031. FileInfoFunction(getCTime, FS_CTIME)
  1032. /* }}} */
  1033. /* {{{ Get file type */
  1034. FileInfoFunction(getType, FS_TYPE)
  1035. /* }}} */
  1036. /* {{{ Returns true if file can be written */
  1037. FileInfoFunction(isWritable, FS_IS_W)
  1038. /* }}} */
  1039. /* {{{ Returns true if file can be read */
  1040. FileInfoFunction(isReadable, FS_IS_R)
  1041. /* }}} */
  1042. /* {{{ Returns true if file is executable */
  1043. FileInfoFunction(isExecutable, FS_IS_X)
  1044. /* }}} */
  1045. /* {{{ Returns true if file is a regular file */
  1046. FileInfoFunction(isFile, FS_IS_FILE)
  1047. /* }}} */
  1048. /* {{{ Returns true if file is directory */
  1049. FileInfoFunction(isDir, FS_IS_DIR)
  1050. /* }}} */
  1051. /* {{{ Returns true if file is symbolic link */
  1052. FileInfoFunction(isLink, FS_IS_LINK)
  1053. /* }}} */
  1054. /* {{{ Return the target of a symbolic link */
  1055. PHP_METHOD(SplFileInfo, getLinkTarget)
  1056. {
  1057. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1058. ssize_t ret;
  1059. char buff[MAXPATHLEN];
  1060. if (zend_parse_parameters_none() == FAILURE) {
  1061. RETURN_THROWS();
  1062. }
  1063. if (intern->file_name == NULL) {
  1064. if (spl_filesystem_object_get_file_name(intern) != SUCCESS) {
  1065. RETURN_THROWS();
  1066. }
  1067. }
  1068. #if defined(PHP_WIN32) || defined(HAVE_SYMLINK)
  1069. if (intern->file_name == NULL) {
  1070. zend_value_error("Filename cannot be empty");
  1071. RETURN_THROWS();
  1072. }
  1073. if (!IS_ABSOLUTE_PATH(ZSTR_VAL(intern->file_name), ZSTR_LEN(intern->file_name))) {
  1074. char expanded_path[MAXPATHLEN];
  1075. if (!expand_filepath_with_mode(ZSTR_VAL(intern->file_name), expanded_path, NULL, 0, CWD_EXPAND )) {
  1076. php_error_docref(NULL, E_WARNING, "No such file or directory");
  1077. RETURN_FALSE;
  1078. }
  1079. ret = php_sys_readlink(expanded_path, buff, MAXPATHLEN - 1);
  1080. } else {
  1081. ret = php_sys_readlink(ZSTR_VAL(intern->file_name), buff, MAXPATHLEN-1);
  1082. }
  1083. #else
  1084. ret = -1; /* always fail if not implemented */
  1085. #endif
  1086. if (ret == -1) {
  1087. zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Unable to read link %s, error: %s", ZSTR_VAL(intern->file_name), strerror(errno));
  1088. RETVAL_FALSE;
  1089. } else {
  1090. /* Append NULL to the end of the string */
  1091. buff[ret] = '\0';
  1092. RETVAL_STRINGL(buff, ret);
  1093. }
  1094. }
  1095. /* }}} */
  1096. /* {{{ Return the resolved path */
  1097. PHP_METHOD(SplFileInfo, getRealPath)
  1098. {
  1099. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1100. char buff[MAXPATHLEN];
  1101. char *filename;
  1102. if (zend_parse_parameters_none() == FAILURE) {
  1103. RETURN_THROWS();
  1104. }
  1105. if (intern->type == SPL_FS_DIR && !intern->file_name && intern->u.dir.entry.d_name[0]) {
  1106. if (spl_filesystem_object_get_file_name(intern) != SUCCESS) {
  1107. RETURN_THROWS();
  1108. }
  1109. }
  1110. if (intern->orig_path) {
  1111. filename = ZSTR_VAL(intern->orig_path);
  1112. } else {
  1113. filename = intern->file_name ? ZSTR_VAL(intern->file_name) : NULL;
  1114. }
  1115. if (filename && VCWD_REALPATH(filename, buff)) {
  1116. #ifdef ZTS
  1117. if (VCWD_ACCESS(buff, F_OK)) {
  1118. RETVAL_FALSE;
  1119. } else
  1120. #endif
  1121. RETVAL_STRING(buff);
  1122. } else {
  1123. RETVAL_FALSE;
  1124. }
  1125. }
  1126. /* }}} */
  1127. /* {{{ Open the current file */
  1128. PHP_METHOD(SplFileInfo, openFile)
  1129. {
  1130. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1131. spl_filesystem_object_create_type(ZEND_NUM_ARGS(), intern, SPL_FS_FILE, NULL, return_value);
  1132. }
  1133. /* }}} */
  1134. /* {{{ Class to use in openFile() */
  1135. PHP_METHOD(SplFileInfo, setFileClass)
  1136. {
  1137. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1138. zend_class_entry *ce = spl_ce_SplFileObject;
  1139. if (zend_parse_parameters(ZEND_NUM_ARGS(), "|C", &ce) == FAILURE) {
  1140. RETURN_THROWS();
  1141. }
  1142. intern->file_class = ce;
  1143. }
  1144. /* }}} */
  1145. /* {{{ Class to use in getFileInfo(), getPathInfo() */
  1146. PHP_METHOD(SplFileInfo, setInfoClass)
  1147. {
  1148. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1149. zend_class_entry *ce = spl_ce_SplFileInfo;
  1150. if (zend_parse_parameters(ZEND_NUM_ARGS(), "|C", &ce) == FAILURE) {
  1151. RETURN_THROWS();
  1152. }
  1153. intern->info_class = ce;
  1154. }
  1155. /* }}} */
  1156. /* {{{ Get/copy file info */
  1157. PHP_METHOD(SplFileInfo, getFileInfo)
  1158. {
  1159. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1160. zend_class_entry *ce = intern->info_class;
  1161. if (zend_parse_parameters(ZEND_NUM_ARGS(), "|C!", &ce) == FAILURE) {
  1162. RETURN_THROWS();
  1163. }
  1164. spl_filesystem_object_create_type(ZEND_NUM_ARGS(), intern, SPL_FS_INFO, ce, return_value);
  1165. }
  1166. /* }}} */
  1167. /* {{{ Get/copy file info */
  1168. PHP_METHOD(SplFileInfo, getPathInfo)
  1169. {
  1170. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1171. zend_class_entry *ce = intern->info_class;
  1172. zend_string *path;
  1173. if (zend_parse_parameters(ZEND_NUM_ARGS(), "|C!", &ce) == FAILURE) {
  1174. RETURN_THROWS();
  1175. }
  1176. path = spl_filesystem_object_get_pathname(intern);
  1177. if (path && ZSTR_LEN(path)) {
  1178. zend_string *dpath = zend_string_init(ZSTR_VAL(path), ZSTR_LEN(path), 0);
  1179. ZSTR_LEN(dpath) = php_dirname(ZSTR_VAL(dpath), ZSTR_LEN(path));
  1180. spl_filesystem_object_create_info(intern, dpath, ce, return_value);
  1181. zend_string_release(dpath);
  1182. }
  1183. }
  1184. /* }}} */
  1185. /* {{{ */
  1186. PHP_METHOD(SplFileInfo, __debugInfo)
  1187. {
  1188. if (zend_parse_parameters_none() == FAILURE) {
  1189. return;
  1190. }
  1191. RETURN_ARR(spl_filesystem_object_get_debug_info(Z_OBJ_P(ZEND_THIS)));
  1192. } /* }}} */
  1193. /* {{{ */
  1194. PHP_METHOD(SplFileInfo, _bad_state_ex)
  1195. {
  1196. zend_throw_error(NULL, "The parent constructor was not called: the object is in an invalid state");
  1197. }
  1198. /* }}} */
  1199. /* {{{ Cronstructs a new dir iterator from a path. */
  1200. PHP_METHOD(FilesystemIterator, __construct)
  1201. {
  1202. spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIT_CTOR_FLAGS | SPL_FILE_DIR_SKIPDOTS);
  1203. }
  1204. /* }}} */
  1205. /* {{{ Rewind dir back to the start */
  1206. PHP_METHOD(FilesystemIterator, rewind)
  1207. {
  1208. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1209. int skip_dots = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_SKIPDOTS);
  1210. if (zend_parse_parameters_none() == FAILURE) {
  1211. RETURN_THROWS();
  1212. }
  1213. intern->u.dir.index = 0;
  1214. if (intern->u.dir.dirp) {
  1215. php_stream_rewinddir(intern->u.dir.dirp);
  1216. }
  1217. do {
  1218. spl_filesystem_dir_read(intern);
  1219. } while (skip_dots && spl_filesystem_is_dot(intern->u.dir.entry.d_name));
  1220. }
  1221. /* }}} */
  1222. /* {{{ Get handling flags */
  1223. PHP_METHOD(FilesystemIterator, getFlags)
  1224. {
  1225. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1226. if (zend_parse_parameters_none() == FAILURE) {
  1227. RETURN_THROWS();
  1228. }
  1229. RETURN_LONG(intern->flags & (SPL_FILE_DIR_KEY_MODE_MASK | SPL_FILE_DIR_CURRENT_MODE_MASK | SPL_FILE_DIR_OTHERS_MASK));
  1230. } /* }}} */
  1231. /* {{{ Set handling flags */
  1232. PHP_METHOD(FilesystemIterator, setFlags)
  1233. {
  1234. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1235. zend_long flags;
  1236. if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &flags) == FAILURE) {
  1237. RETURN_THROWS();
  1238. }
  1239. intern->flags &= ~(SPL_FILE_DIR_KEY_MODE_MASK|SPL_FILE_DIR_CURRENT_MODE_MASK|SPL_FILE_DIR_OTHERS_MASK);
  1240. intern->flags |= ((SPL_FILE_DIR_KEY_MODE_MASK|SPL_FILE_DIR_CURRENT_MODE_MASK|SPL_FILE_DIR_OTHERS_MASK) & flags);
  1241. } /* }}} */
  1242. /* {{{ Returns whether current entry is a directory and not '.' or '..' */
  1243. PHP_METHOD(RecursiveDirectoryIterator, hasChildren)
  1244. {
  1245. bool allow_links = 0;
  1246. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1247. ZEND_PARSE_PARAMETERS_START(0, 1)
  1248. Z_PARAM_OPTIONAL
  1249. Z_PARAM_BOOL(allow_links)
  1250. ZEND_PARSE_PARAMETERS_END();
  1251. if (spl_filesystem_is_invalid_or_dot(intern->u.dir.entry.d_name)) {
  1252. RETURN_FALSE;
  1253. } else {
  1254. if (spl_filesystem_object_get_file_name(intern) != SUCCESS) {
  1255. RETURN_THROWS();
  1256. }
  1257. php_stat(intern->file_name, FS_LPERMS, return_value);
  1258. if (Z_TYPE_P(return_value) == IS_FALSE) {
  1259. return;
  1260. } else if (!S_ISLNK(Z_LVAL_P(return_value))) {
  1261. RETURN_BOOL(S_ISDIR(Z_LVAL_P(return_value)));
  1262. } else {
  1263. if (!allow_links
  1264. && !(intern->flags & SPL_FILE_DIR_FOLLOW_SYMLINKS)) {
  1265. RETURN_FALSE;
  1266. }
  1267. php_stat(intern->file_name, FS_IS_DIR, return_value);
  1268. }
  1269. }
  1270. }
  1271. /* }}} */
  1272. /* {{{ Returns an iterator for the current entry if it is a directory */
  1273. PHP_METHOD(RecursiveDirectoryIterator, getChildren)
  1274. {
  1275. zval zpath, zflags;
  1276. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1277. spl_filesystem_object *subdir;
  1278. char slash = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_UNIXPATHS) ? '/' : DEFAULT_SLASH;
  1279. if (zend_parse_parameters_none() == FAILURE) {
  1280. RETURN_THROWS();
  1281. }
  1282. if (spl_filesystem_object_get_file_name(intern) != SUCCESS) {
  1283. RETURN_THROWS();
  1284. }
  1285. ZVAL_LONG(&zflags, intern->flags);
  1286. ZVAL_STR_COPY(&zpath, intern->file_name);
  1287. spl_instantiate_arg_ex2(Z_OBJCE_P(ZEND_THIS), return_value, &zpath, &zflags);
  1288. zval_ptr_dtor(&zpath);
  1289. subdir = Z_SPLFILESYSTEM_P(return_value);
  1290. if (subdir) {
  1291. size_t name_len = strlen(intern->u.dir.entry.d_name);
  1292. if (intern->u.dir.sub_path && ZSTR_LEN(intern->u.dir.sub_path)) {
  1293. zend_string *sub_path = zend_string_alloc(ZSTR_LEN(intern->u.dir.sub_path) + 1 + name_len, 0);
  1294. memcpy(ZSTR_VAL(sub_path), ZSTR_VAL(intern->u.dir.sub_path), ZSTR_LEN(intern->u.dir.sub_path));
  1295. ZSTR_VAL(sub_path)[ZSTR_LEN(intern->u.dir.sub_path)] = slash;
  1296. memcpy(ZSTR_VAL(sub_path) + ZSTR_LEN(intern->u.dir.sub_path) + 1, intern->u.dir.entry.d_name, name_len);
  1297. ZSTR_VAL(sub_path)[ZSTR_LEN(intern->u.dir.sub_path) + 1 + name_len] = 0;
  1298. subdir->u.dir.sub_path = sub_path;
  1299. } else {
  1300. subdir->u.dir.sub_path = zend_string_init(intern->u.dir.entry.d_name, name_len, 0);
  1301. }
  1302. subdir->info_class = intern->info_class;
  1303. subdir->file_class = intern->file_class;
  1304. subdir->oth = intern->oth;
  1305. }
  1306. }
  1307. /* }}} */
  1308. /* {{{ Get sub path */
  1309. PHP_METHOD(RecursiveDirectoryIterator, getSubPath)
  1310. {
  1311. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1312. if (zend_parse_parameters_none() == FAILURE) {
  1313. RETURN_THROWS();
  1314. }
  1315. if (intern->u.dir.sub_path) {
  1316. RETURN_STR_COPY(intern->u.dir.sub_path);
  1317. } else {
  1318. RETURN_EMPTY_STRING();
  1319. }
  1320. }
  1321. /* }}} */
  1322. /* {{{ Get sub path and file name */
  1323. PHP_METHOD(RecursiveDirectoryIterator, getSubPathname)
  1324. {
  1325. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1326. char slash = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_UNIXPATHS) ? '/' : DEFAULT_SLASH;
  1327. if (zend_parse_parameters_none() == FAILURE) {
  1328. RETURN_THROWS();
  1329. }
  1330. if (intern->u.dir.sub_path) {
  1331. RETURN_NEW_STR(strpprintf(0, "%s%c%s", ZSTR_VAL(intern->u.dir.sub_path), slash, intern->u.dir.entry.d_name));
  1332. } else {
  1333. RETURN_STRING(intern->u.dir.entry.d_name);
  1334. }
  1335. }
  1336. /* }}} */
  1337. /* {{{ Cronstructs a new dir iterator from a path. */
  1338. PHP_METHOD(RecursiveDirectoryIterator, __construct)
  1339. {
  1340. spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIT_CTOR_FLAGS);
  1341. }
  1342. /* }}} */
  1343. #ifdef HAVE_GLOB
  1344. /* {{{ Cronstructs a new dir iterator from a glob expression (no glob:// needed). */
  1345. PHP_METHOD(GlobIterator, __construct)
  1346. {
  1347. spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIT_CTOR_FLAGS|DIT_CTOR_GLOB);
  1348. }
  1349. /* }}} */
  1350. /* {{{ Return the number of directories and files found by globbing */
  1351. PHP_METHOD(GlobIterator, count)
  1352. {
  1353. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1354. if (zend_parse_parameters_none() == FAILURE) {
  1355. RETURN_THROWS();
  1356. }
  1357. if (intern->u.dir.dirp && php_stream_is(intern->u.dir.dirp ,&php_glob_stream_ops)) {
  1358. RETURN_LONG(php_glob_stream_get_count(intern->u.dir.dirp, NULL));
  1359. } else {
  1360. /* should not happen */
  1361. // TODO ZEND_ASSERT ?
  1362. php_error_docref(NULL, E_ERROR, "GlobIterator lost glob state");
  1363. }
  1364. }
  1365. /* }}} */
  1366. #endif /* HAVE_GLOB */
  1367. /* {{{ forward declarations to the iterator handlers */
  1368. static void spl_filesystem_dir_it_dtor(zend_object_iterator *iter);
  1369. static int spl_filesystem_dir_it_valid(zend_object_iterator *iter);
  1370. static zval *spl_filesystem_dir_it_current_data(zend_object_iterator *iter);
  1371. static void spl_filesystem_dir_it_current_key(zend_object_iterator *iter, zval *key);
  1372. static void spl_filesystem_dir_it_move_forward(zend_object_iterator *iter);
  1373. static void spl_filesystem_dir_it_rewind(zend_object_iterator *iter);
  1374. /* iterator handler table */
  1375. static const zend_object_iterator_funcs spl_filesystem_dir_it_funcs = {
  1376. spl_filesystem_dir_it_dtor,
  1377. spl_filesystem_dir_it_valid,
  1378. spl_filesystem_dir_it_current_data,
  1379. spl_filesystem_dir_it_current_key,
  1380. spl_filesystem_dir_it_move_forward,
  1381. spl_filesystem_dir_it_rewind,
  1382. NULL,
  1383. NULL, /* get_gc */
  1384. };
  1385. /* }}} */
  1386. /* {{{ spl_ce_dir_get_iterator */
  1387. zend_object_iterator *spl_filesystem_dir_get_iterator(zend_class_entry *ce, zval *object, int by_ref)
  1388. {
  1389. spl_filesystem_iterator *iterator;
  1390. spl_filesystem_object *dir_object;
  1391. if (by_ref) {
  1392. zend_throw_error(NULL, "An iterator cannot be used with foreach by reference");
  1393. return NULL;
  1394. }
  1395. dir_object = Z_SPLFILESYSTEM_P(object);
  1396. iterator = spl_filesystem_object_to_iterator(dir_object);
  1397. ZVAL_OBJ_COPY(&iterator->intern.data, Z_OBJ_P(object));
  1398. iterator->intern.funcs = &spl_filesystem_dir_it_funcs;
  1399. /* ->current must be initialized; rewind doesn't set it and valid
  1400. * doesn't check whether it's set */
  1401. iterator->current = *object;
  1402. return &iterator->intern;
  1403. }
  1404. /* }}} */
  1405. /* {{{ spl_filesystem_dir_it_dtor */
  1406. static void spl_filesystem_dir_it_dtor(zend_object_iterator *iter)
  1407. {
  1408. spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter;
  1409. zval_ptr_dtor(&iterator->intern.data);
  1410. }
  1411. /* }}} */
  1412. /* {{{ spl_filesystem_dir_it_valid */
  1413. static int spl_filesystem_dir_it_valid(zend_object_iterator *iter)
  1414. {
  1415. spl_filesystem_object *object = spl_filesystem_iterator_to_object((spl_filesystem_iterator *)iter);
  1416. return object->u.dir.entry.d_name[0] != '\0' ? SUCCESS : FAILURE;
  1417. }
  1418. /* }}} */
  1419. /* {{{ spl_filesystem_dir_it_current_data */
  1420. static zval *spl_filesystem_dir_it_current_data(zend_object_iterator *iter)
  1421. {
  1422. spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter;
  1423. return &iterator->current;
  1424. }
  1425. /* }}} */
  1426. /* {{{ spl_filesystem_dir_it_current_key */
  1427. static void spl_filesystem_dir_it_current_key(zend_object_iterator *iter, zval *key)
  1428. {
  1429. spl_filesystem_object *object = spl_filesystem_iterator_to_object((spl_filesystem_iterator *)iter);
  1430. ZVAL_LONG(key, object->u.dir.index);
  1431. }
  1432. /* }}} */
  1433. /* {{{ spl_filesystem_dir_it_move_forward */
  1434. static void spl_filesystem_dir_it_move_forward(zend_object_iterator *iter)
  1435. {
  1436. spl_filesystem_object *object = spl_filesystem_iterator_to_object((spl_filesystem_iterator *)iter);
  1437. object->u.dir.index++;
  1438. spl_filesystem_dir_read(object);
  1439. if (object->file_name) {
  1440. zend_string_release(object->file_name);
  1441. object->file_name = NULL;
  1442. }
  1443. }
  1444. /* }}} */
  1445. /* {{{ spl_filesystem_dir_it_rewind */
  1446. static void spl_filesystem_dir_it_rewind(zend_object_iterator *iter)
  1447. {
  1448. spl_filesystem_object *object = spl_filesystem_iterator_to_object((spl_filesystem_iterator *)iter);
  1449. object->u.dir.index = 0;
  1450. if (object->u.dir.dirp) {
  1451. php_stream_rewinddir(object->u.dir.dirp);
  1452. }
  1453. spl_filesystem_dir_read(object);
  1454. }
  1455. /* }}} */
  1456. /* {{{ spl_filesystem_tree_it_dtor */
  1457. static void spl_filesystem_tree_it_dtor(zend_object_iterator *iter)
  1458. {
  1459. spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter;
  1460. zval_ptr_dtor(&iterator->intern.data);
  1461. zval_ptr_dtor(&iterator->current);
  1462. }
  1463. /* }}} */
  1464. /* {{{ spl_filesystem_tree_it_current_data */
  1465. static zval *spl_filesystem_tree_it_current_data(zend_object_iterator *iter)
  1466. {
  1467. spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter;
  1468. spl_filesystem_object *object = spl_filesystem_iterator_to_object(iterator);
  1469. if (SPL_FILE_DIR_CURRENT(object, SPL_FILE_DIR_CURRENT_AS_PATHNAME)) {
  1470. if (Z_ISUNDEF(iterator->current)) {
  1471. if (spl_filesystem_object_get_file_name(object) != SUCCESS) {
  1472. return NULL;
  1473. }
  1474. ZVAL_STR_COPY(&iterator->current, object->file_name);
  1475. }
  1476. return &iterator->current;
  1477. } else if (SPL_FILE_DIR_CURRENT(object, SPL_FILE_DIR_CURRENT_AS_FILEINFO)) {
  1478. if (Z_ISUNDEF(iterator->current)) {
  1479. if (spl_filesystem_object_get_file_name(object) != SUCCESS) {
  1480. return NULL;
  1481. }
  1482. spl_filesystem_object_create_type(0, object, SPL_FS_INFO, NULL, &iterator->current);
  1483. }
  1484. return &iterator->current;
  1485. } else {
  1486. return &iterator->intern.data;
  1487. }
  1488. }
  1489. /* }}} */
  1490. /* {{{ spl_filesystem_tree_it_current_key */
  1491. static void spl_filesystem_tree_it_current_key(zend_object_iterator *iter, zval *key)
  1492. {
  1493. spl_filesystem_object *object = spl_filesystem_iterator_to_object((spl_filesystem_iterator *)iter);
  1494. if (SPL_FILE_DIR_KEY(object, SPL_FILE_DIR_KEY_AS_FILENAME)) {
  1495. ZVAL_STRING(key, object->u.dir.entry.d_name);
  1496. } else {
  1497. if (spl_filesystem_object_get_file_name(object) != SUCCESS) {
  1498. return;
  1499. }
  1500. ZVAL_STR_COPY(key, object->file_name);
  1501. }
  1502. }
  1503. /* }}} */
  1504. /* {{{ spl_filesystem_tree_it_move_forward */
  1505. static void spl_filesystem_tree_it_move_forward(zend_object_iterator *iter)
  1506. {
  1507. spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter;
  1508. spl_filesystem_object *object = spl_filesystem_iterator_to_object(iterator);
  1509. object->u.dir.index++;
  1510. do {
  1511. spl_filesystem_dir_read(object);
  1512. } while (spl_filesystem_is_dot(object->u.dir.entry.d_name));
  1513. if (object->file_name) {
  1514. zend_string_release(object->file_name);
  1515. object->file_name = NULL;
  1516. }
  1517. if (!Z_ISUNDEF(iterator->current)) {
  1518. zval_ptr_dtor(&iterator->current);
  1519. ZVAL_UNDEF(&iterator->current);
  1520. }
  1521. }
  1522. /* }}} */
  1523. /* {{{ spl_filesystem_tree_it_rewind */
  1524. static void spl_filesystem_tree_it_rewind(zend_object_iterator *iter)
  1525. {
  1526. spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter;
  1527. spl_filesystem_object *object = spl_filesystem_iterator_to_object(iterator);
  1528. object->u.dir.index = 0;
  1529. if (object->u.dir.dirp) {
  1530. php_stream_rewinddir(object->u.dir.dirp);
  1531. }
  1532. do {
  1533. spl_filesystem_dir_read(object);
  1534. } while (spl_filesystem_is_dot(object->u.dir.entry.d_name));
  1535. if (!Z_ISUNDEF(iterator->current)) {
  1536. zval_ptr_dtor(&iterator->current);
  1537. ZVAL_UNDEF(&iterator->current);
  1538. }
  1539. }
  1540. /* }}} */
  1541. /* {{{ iterator handler table */
  1542. static const zend_object_iterator_funcs spl_filesystem_tree_it_funcs = {
  1543. spl_filesystem_tree_it_dtor,
  1544. spl_filesystem_dir_it_valid,
  1545. spl_filesystem_tree_it_current_data,
  1546. spl_filesystem_tree_it_current_key,
  1547. spl_filesystem_tree_it_move_forward,
  1548. spl_filesystem_tree_it_rewind,
  1549. NULL,
  1550. NULL, /* get_gc */
  1551. };
  1552. /* }}} */
  1553. /* {{{ spl_ce_dir_get_iterator */
  1554. zend_object_iterator *spl_filesystem_tree_get_iterator(zend_class_entry *ce, zval *object, int by_ref)
  1555. {
  1556. spl_filesystem_iterator *iterator;
  1557. spl_filesystem_object *dir_object;
  1558. if (by_ref) {
  1559. zend_throw_error(NULL, "An iterator cannot be used with foreach by reference");
  1560. return NULL;
  1561. }
  1562. dir_object = Z_SPLFILESYSTEM_P(object);
  1563. iterator = spl_filesystem_object_to_iterator(dir_object);
  1564. ZVAL_OBJ_COPY(&iterator->intern.data, Z_OBJ_P(object));
  1565. iterator->intern.funcs = &spl_filesystem_tree_it_funcs;
  1566. return &iterator->intern;
  1567. }
  1568. /* }}} */
  1569. /* {{{ spl_filesystem_object_cast */
  1570. static int spl_filesystem_object_cast(zend_object *readobj, zval *writeobj, int type)
  1571. {
  1572. spl_filesystem_object *intern = spl_filesystem_from_obj(readobj);
  1573. if (type == IS_STRING) {
  1574. if (readobj->ce->__tostring) {
  1575. return zend_std_cast_object_tostring(readobj, writeobj, type);
  1576. }
  1577. switch (intern->type) {
  1578. case SPL_FS_INFO:
  1579. case SPL_FS_FILE:
  1580. ZVAL_STR_COPY(writeobj, intern->file_name);
  1581. return SUCCESS;
  1582. case SPL_FS_DIR:
  1583. ZVAL_STRING(writeobj, intern->u.dir.entry.d_name);
  1584. return SUCCESS;
  1585. }
  1586. } else if (type == _IS_BOOL) {
  1587. ZVAL_TRUE(writeobj);
  1588. return SUCCESS;
  1589. }
  1590. ZVAL_NULL(writeobj);
  1591. return FAILURE;
  1592. }
  1593. /* }}} */
  1594. static zend_result spl_filesystem_file_read_ex(spl_filesystem_object *intern, bool silent, zend_long line_add) /* {{{ */
  1595. {
  1596. char *buf;
  1597. size_t line_len = 0;
  1598. spl_filesystem_file_free_line(intern);
  1599. if (php_stream_eof(intern->u.file.stream)) {
  1600. if (!silent) {
  1601. zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Cannot read from file %s", ZSTR_VAL(intern->file_name));
  1602. }
  1603. return FAILURE;
  1604. }
  1605. if (intern->u.file.max_line_len > 0) {
  1606. buf = safe_emalloc((intern->u.file.max_line_len + 1), sizeof(char), 0);
  1607. if (php_stream_get_line(intern->u.file.stream, buf, intern->u.file.max_line_len + 1, &line_len) == NULL) {
  1608. efree(buf);
  1609. buf = NULL;
  1610. } else {
  1611. buf[line_len] = '\0';
  1612. }
  1613. } else {
  1614. buf = php_stream_get_line(intern->u.file.stream, NULL, 0, &line_len);
  1615. }
  1616. if (!buf) {
  1617. intern->u.file.current_line = estrdup("");
  1618. intern->u.file.current_line_len = 0;
  1619. } else {
  1620. if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_DROP_NEW_LINE)) {
  1621. if (line_len > 0 && buf[line_len - 1] == '\n') {
  1622. line_len--;
  1623. if (line_len > 0 && buf[line_len - 1] == '\r') {
  1624. line_len--;
  1625. }
  1626. buf[line_len] = '\0';
  1627. }
  1628. }
  1629. intern->u.file.current_line = buf;
  1630. intern->u.file.current_line_len = line_len;
  1631. }
  1632. intern->u.file.current_line_num += line_add;
  1633. return SUCCESS;
  1634. } /* }}} */
  1635. static inline zend_result spl_filesystem_file_read(spl_filesystem_object *intern, bool silent)
  1636. {
  1637. zend_long line_add = (intern->u.file.current_line) ? 1 : 0;
  1638. return spl_filesystem_file_read_ex(intern, silent, line_add);
  1639. }
  1640. static zend_result spl_filesystem_file_read_csv(spl_filesystem_object *intern, char delimiter, char enclosure, int escape, zval *return_value) /* {{{ */
  1641. {
  1642. do {
  1643. int ret = spl_filesystem_file_read(intern, 1);
  1644. if (ret != SUCCESS) {
  1645. return ret;
  1646. }
  1647. } while (!intern->u.file.current_line_len && SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_SKIP_EMPTY));
  1648. size_t buf_len = intern->u.file.current_line_len;
  1649. char *buf = estrndup(intern->u.file.current_line, buf_len);
  1650. if (!Z_ISUNDEF(intern->u.file.current_zval)) {
  1651. zval_ptr_dtor(&intern->u.file.current_zval);
  1652. ZVAL_UNDEF(&intern->u.file.current_zval);
  1653. }
  1654. php_fgetcsv(intern->u.file.stream, delimiter, enclosure, escape, buf_len, buf, &intern->u.file.current_zval);
  1655. if (return_value) {
  1656. ZVAL_COPY(return_value, &intern->u.file.current_zval);
  1657. }
  1658. return SUCCESS;
  1659. }
  1660. /* }}} */
  1661. static int spl_filesystem_file_read_line_ex(zval * this_ptr, spl_filesystem_object *intern, int silent) /* {{{ */
  1662. {
  1663. zval retval;
  1664. /* 1) use fgetcsv? 2) overloaded call the function, 3) do it directly */
  1665. if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_CSV)) {
  1666. return spl_filesystem_file_read_csv(intern, intern->u.file.delimiter, intern->u.file.enclosure, intern->u.file.escape, NULL);
  1667. }
  1668. if (intern->u.file.func_getCurr->common.scope != spl_ce_SplFileObject) {
  1669. zend_execute_data *execute_data = EG(current_execute_data);
  1670. spl_filesystem_file_free_line(intern);
  1671. if (php_stream_eof(intern->u.file.stream)) {
  1672. if (!silent) {
  1673. zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Cannot read from file %s", ZSTR_VAL(intern->file_name));
  1674. }
  1675. return FAILURE;
  1676. }
  1677. zend_call_method_with_0_params(Z_OBJ_P(this_ptr), Z_OBJCE_P(ZEND_THIS), &intern->u.file.func_getCurr, "getCurrentLine", &retval);
  1678. if (Z_ISUNDEF(retval)) {
  1679. return FAILURE;
  1680. }
  1681. if (Z_TYPE(retval) != IS_STRING) {
  1682. zend_type_error("%s::getCurrentLine(): Return value must be of type string, %s returned",
  1683. ZSTR_VAL(Z_OBJCE_P(ZEND_THIS)->name), zend_zval_type_name(&retval));
  1684. zval_ptr_dtor(&retval);
  1685. return FAILURE;
  1686. }
  1687. if (intern->u.file.current_line || !Z_ISUNDEF(intern->u.file.current_zval)) {
  1688. intern->u.file.current_line_num++;
  1689. }
  1690. spl_filesystem_file_free_line(intern);
  1691. intern->u.file.current_line = estrndup(Z_STRVAL(retval), Z_STRLEN(retval));
  1692. intern->u.file.current_line_len = Z_STRLEN(retval);
  1693. zval_ptr_dtor(&retval);
  1694. return SUCCESS;
  1695. } else {
  1696. return spl_filesystem_file_read(intern, silent);
  1697. }
  1698. } /* }}} */
  1699. static int spl_filesystem_file_is_empty_line(spl_filesystem_object *intern) /* {{{ */
  1700. {
  1701. if (intern->u.file.current_line) {
  1702. return intern->u.file.current_line_len == 0;
  1703. } else if (!Z_ISUNDEF(intern->u.file.current_zval)) {
  1704. switch(Z_TYPE(intern->u.file.current_zval)) {
  1705. case IS_STRING:
  1706. return Z_STRLEN(intern->u.file.current_zval) == 0;
  1707. case IS_ARRAY:
  1708. if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_CSV)
  1709. && zend_hash_num_elements(Z_ARRVAL(intern->u.file.current_zval)) == 1) {
  1710. uint32_t idx = 0;
  1711. zval *first;
  1712. while (Z_ISUNDEF(Z_ARRVAL(intern->u.file.current_zval)->arData[idx].val)) {
  1713. idx++;
  1714. }
  1715. first = &Z_ARRVAL(intern->u.file.current_zval)->arData[idx].val;
  1716. return Z_TYPE_P(first) == IS_STRING && Z_STRLEN_P(first) == 0;
  1717. }
  1718. return zend_hash_num_elements(Z_ARRVAL(intern->u.file.current_zval)) == 0;
  1719. case IS_NULL:
  1720. return 1;
  1721. default:
  1722. return 0;
  1723. }
  1724. } else {
  1725. return 1;
  1726. }
  1727. }
  1728. /* }}} */
  1729. static int spl_filesystem_file_read_line(zval * this_ptr, spl_filesystem_object *intern, int silent) /* {{{ */
  1730. {
  1731. int ret = spl_filesystem_file_read_line_ex(this_ptr, intern, silent);
  1732. while (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_SKIP_EMPTY) && ret == SUCCESS && spl_filesystem_file_is_empty_line(intern)) {
  1733. spl_filesystem_file_free_line(intern);
  1734. ret = spl_filesystem_file_read_line_ex(this_ptr, intern, silent);
  1735. }
  1736. return ret;
  1737. }
  1738. /* }}} */
  1739. static void spl_filesystem_file_rewind(zval * this_ptr, spl_filesystem_object *intern) /* {{{ */
  1740. {
  1741. if (!intern->u.file.stream) {
  1742. zend_throw_error(NULL, "Object not initialized");
  1743. return;
  1744. }
  1745. if (-1 == php_stream_rewind(intern->u.file.stream)) {
  1746. zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Cannot rewind file %s", ZSTR_VAL(intern->file_name));
  1747. } else {
  1748. spl_filesystem_file_free_line(intern);
  1749. intern->u.file.current_line_num = 0;
  1750. }
  1751. if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_AHEAD)) {
  1752. spl_filesystem_file_read_line(this_ptr, intern, 1);
  1753. }
  1754. } /* }}} */
  1755. /* {{{ Construct a new file object */
  1756. PHP_METHOD(SplFileObject, __construct)
  1757. {
  1758. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1759. zend_string *open_mode = ZSTR_CHAR('r');
  1760. bool use_include_path = 0;
  1761. size_t path_len;
  1762. zend_error_handling error_handling;
  1763. intern->u.file.open_mode = ZSTR_CHAR('r');
  1764. if (zend_parse_parameters(ZEND_NUM_ARGS(), "P|Sbr!",
  1765. &intern->file_name, &open_mode,
  1766. &use_include_path, &intern->u.file.zcontext) == FAILURE) {
  1767. intern->u.file.open_mode = NULL;
  1768. intern->file_name = NULL;
  1769. RETURN_THROWS();
  1770. }
  1771. intern->u.file.open_mode = zend_string_copy(open_mode);
  1772. /* spl_filesystem_file_open() can generate E_WARNINGs which we want to promote to exceptions */
  1773. zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling);
  1774. zend_result retval = spl_filesystem_file_open(intern, use_include_path);
  1775. zend_restore_error_handling(&error_handling);
  1776. if (retval == FAILURE) {
  1777. RETURN_THROWS();
  1778. }
  1779. path_len = strlen(intern->u.file.stream->orig_path);
  1780. if (path_len > 1 && IS_SLASH_AT(intern->u.file.stream->orig_path, path_len-1)) {
  1781. path_len--;
  1782. }
  1783. while (path_len > 1 && !IS_SLASH_AT(intern->u.file.stream->orig_path, path_len-1)) {
  1784. path_len--;
  1785. }
  1786. if (path_len) {
  1787. path_len--;
  1788. }
  1789. intern->path = zend_string_init(intern->u.file.stream->orig_path, path_len, 0);
  1790. } /* }}} */
  1791. /* {{{ Construct a new temp file object */
  1792. PHP_METHOD(SplTempFileObject, __construct)
  1793. {
  1794. zend_string *file_name;
  1795. zend_long max_memory = PHP_STREAM_MAX_MEM;
  1796. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1797. zend_error_handling error_handling;
  1798. if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &max_memory) == FAILURE) {
  1799. RETURN_THROWS();
  1800. }
  1801. if (max_memory < 0) {
  1802. file_name = zend_string_init("php://memory", sizeof("php://memory")-1, 0);
  1803. } else if (ZEND_NUM_ARGS()) {
  1804. file_name = zend_strpprintf(0, "php://temp/maxmemory:" ZEND_LONG_FMT, max_memory);
  1805. } else {
  1806. file_name = zend_string_init("php://temp", sizeof("php://temp")-1, 0);
  1807. }
  1808. intern->file_name = file_name;
  1809. intern->u.file.open_mode = zend_string_init("wb", sizeof("wb")-1, 0);
  1810. /* spl_filesystem_file_open() can generate E_WARNINGs which we want to promote to exceptions */
  1811. zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling);
  1812. if (spl_filesystem_file_open(intern, /* use_include_path */ false) == SUCCESS) {
  1813. intern->path = ZSTR_EMPTY_ALLOC();
  1814. }
  1815. zend_string_release(file_name);
  1816. zend_restore_error_handling(&error_handling);
  1817. } /* }}} */
  1818. /* {{{ Rewind the file and read the first line */
  1819. PHP_METHOD(SplFileObject, rewind)
  1820. {
  1821. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1822. if (zend_parse_parameters_none() == FAILURE) {
  1823. RETURN_THROWS();
  1824. }
  1825. spl_filesystem_file_rewind(ZEND_THIS, intern);
  1826. } /* }}} */
  1827. /* {{{ Return whether end of file is reached */
  1828. PHP_METHOD(SplFileObject, eof)
  1829. {
  1830. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1831. if (zend_parse_parameters_none() == FAILURE) {
  1832. RETURN_THROWS();
  1833. }
  1834. CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
  1835. RETURN_BOOL(php_stream_eof(intern->u.file.stream));
  1836. } /* }}} */
  1837. /* {{{ Return !eof() */
  1838. PHP_METHOD(SplFileObject, valid)
  1839. {
  1840. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1841. if (zend_parse_parameters_none() == FAILURE) {
  1842. RETURN_THROWS();
  1843. }
  1844. if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_AHEAD)) {
  1845. RETURN_BOOL(intern->u.file.current_line || !Z_ISUNDEF(intern->u.file.current_zval));
  1846. } else {
  1847. if(!intern->u.file.stream) {
  1848. RETURN_FALSE;
  1849. }
  1850. RETVAL_BOOL(!php_stream_eof(intern->u.file.stream));
  1851. }
  1852. } /* }}} */
  1853. /* {{{ Return next line from file */
  1854. PHP_METHOD(SplFileObject, fgets)
  1855. {
  1856. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1857. if (zend_parse_parameters_none() == FAILURE) {
  1858. RETURN_THROWS();
  1859. }
  1860. CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
  1861. if (spl_filesystem_file_read_ex(intern, /* silent */ false, /* line_add */ 1) == FAILURE) {
  1862. RETURN_THROWS();
  1863. }
  1864. RETURN_STRINGL(intern->u.file.current_line, intern->u.file.current_line_len);
  1865. } /* }}} */
  1866. /* {{{ Return current line from file */
  1867. PHP_METHOD(SplFileObject, current)
  1868. {
  1869. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1870. if (zend_parse_parameters_none() == FAILURE) {
  1871. RETURN_THROWS();
  1872. }
  1873. CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
  1874. if (!intern->u.file.current_line && Z_ISUNDEF(intern->u.file.current_zval)) {
  1875. spl_filesystem_file_read_line(ZEND_THIS, intern, 1);
  1876. }
  1877. if (intern->u.file.current_line && (!SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_CSV) || Z_ISUNDEF(intern->u.file.current_zval))) {
  1878. RETURN_STRINGL(intern->u.file.current_line, intern->u.file.current_line_len);
  1879. } else if (!Z_ISUNDEF(intern->u.file.current_zval)) {
  1880. ZEND_ASSERT(!Z_ISREF(intern->u.file.current_zval));
  1881. RETURN_COPY(&intern->u.file.current_zval);
  1882. }
  1883. RETURN_FALSE;
  1884. } /* }}} */
  1885. /* {{{ Return line number */
  1886. PHP_METHOD(SplFileObject, key)
  1887. {
  1888. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1889. if (zend_parse_parameters_none() == FAILURE) {
  1890. RETURN_THROWS();
  1891. }
  1892. /* Do not read the next line to support correct counting with fgetc()
  1893. if (!intern->u.file.current_line) {
  1894. spl_filesystem_file_read_line(ZEND_THIS, intern, 1);
  1895. } */
  1896. RETURN_LONG(intern->u.file.current_line_num);
  1897. } /* }}} */
  1898. /* {{{ Read next line */
  1899. PHP_METHOD(SplFileObject, next)
  1900. {
  1901. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1902. if (zend_parse_parameters_none() == FAILURE) {
  1903. RETURN_THROWS();
  1904. }
  1905. spl_filesystem_file_free_line(intern);
  1906. if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_AHEAD)) {
  1907. spl_filesystem_file_read_line(ZEND_THIS, intern, 1);
  1908. }
  1909. intern->u.file.current_line_num++;
  1910. } /* }}} */
  1911. /* {{{ Set file handling flags */
  1912. PHP_METHOD(SplFileObject, setFlags)
  1913. {
  1914. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1915. if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &intern->flags) == FAILURE) {
  1916. RETURN_THROWS();
  1917. }
  1918. } /* }}} */
  1919. /* {{{ Get file handling flags */
  1920. PHP_METHOD(SplFileObject, getFlags)
  1921. {
  1922. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1923. if (zend_parse_parameters_none() == FAILURE) {
  1924. RETURN_THROWS();
  1925. }
  1926. RETURN_LONG(intern->flags & SPL_FILE_OBJECT_MASK);
  1927. } /* }}} */
  1928. /* {{{ Set maximum line length */
  1929. PHP_METHOD(SplFileObject, setMaxLineLen)
  1930. {
  1931. zend_long max_len;
  1932. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1933. if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &max_len) == FAILURE) {
  1934. RETURN_THROWS();
  1935. }
  1936. if (max_len < 0) {
  1937. zend_argument_value_error(1, "must be greater than or equal to 0");
  1938. RETURN_THROWS();
  1939. }
  1940. intern->u.file.max_line_len = max_len;
  1941. } /* }}} */
  1942. /* {{{ Get maximum line length */
  1943. PHP_METHOD(SplFileObject, getMaxLineLen)
  1944. {
  1945. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1946. if (zend_parse_parameters_none() == FAILURE) {
  1947. RETURN_THROWS();
  1948. }
  1949. RETURN_LONG((zend_long)intern->u.file.max_line_len);
  1950. } /* }}} */
  1951. /* {{{ Return false */
  1952. PHP_METHOD(SplFileObject, hasChildren)
  1953. {
  1954. if (zend_parse_parameters_none() == FAILURE) {
  1955. RETURN_THROWS();
  1956. }
  1957. RETURN_FALSE;
  1958. } /* }}} */
  1959. /* {{{ Read NULL */
  1960. PHP_METHOD(SplFileObject, getChildren)
  1961. {
  1962. if (zend_parse_parameters_none() == FAILURE) {
  1963. RETURN_THROWS();
  1964. }
  1965. /* return NULL */
  1966. } /* }}} */
  1967. /* {{{ Return current line as CSV */
  1968. PHP_METHOD(SplFileObject, fgetcsv)
  1969. {
  1970. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1971. char delimiter = intern->u.file.delimiter, enclosure = intern->u.file.enclosure;
  1972. int escape = intern->u.file.escape;
  1973. char *delim = NULL, *enclo = NULL, *esc = NULL;
  1974. size_t d_len = 0, e_len = 0, esc_len = 0;
  1975. if (zend_parse_parameters(ZEND_NUM_ARGS(), "|sss", &delim, &d_len, &enclo, &e_len, &esc, &esc_len) == FAILURE) {
  1976. RETURN_THROWS();
  1977. }
  1978. CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
  1979. switch (ZEND_NUM_ARGS()) {
  1980. case 3:
  1981. if (esc_len > 1) {
  1982. zend_argument_value_error(3, "must be empty or a single character");
  1983. RETURN_THROWS();
  1984. }
  1985. if (esc_len == 0) {
  1986. escape = PHP_CSV_NO_ESCAPE;
  1987. } else {
  1988. escape = (unsigned char) esc[0];
  1989. }
  1990. ZEND_FALLTHROUGH;
  1991. case 2:
  1992. if (e_len != 1) {
  1993. zend_argument_value_error(2, "must be a single character");
  1994. RETURN_THROWS();
  1995. }
  1996. enclosure = enclo[0];
  1997. ZEND_FALLTHROUGH;
  1998. case 1:
  1999. if (d_len != 1) {
  2000. zend_argument_value_error(1, "must be a single character");
  2001. RETURN_THROWS();
  2002. }
  2003. delimiter = delim[0];
  2004. ZEND_FALLTHROUGH;
  2005. case 0:
  2006. break;
  2007. }
  2008. if (spl_filesystem_file_read_csv(intern, delimiter, enclosure, escape, return_value) == FAILURE) {
  2009. RETURN_FALSE;
  2010. }
  2011. }
  2012. /* }}} */
  2013. /* {{{ Output a field array as a CSV line */
  2014. PHP_METHOD(SplFileObject, fputcsv)
  2015. {
  2016. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  2017. char delimiter = intern->u.file.delimiter, enclosure = intern->u.file.enclosure;
  2018. int escape = intern->u.file.escape;
  2019. char *delim = NULL, *enclo = NULL, *esc = NULL;
  2020. size_t d_len = 0, e_len = 0, esc_len = 0;
  2021. zend_long ret;
  2022. zval *fields = NULL;
  2023. zend_string *eol = NULL;
  2024. if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|sssS", &fields, &delim, &d_len, &enclo, &e_len, &esc, &esc_len, &eol) == SUCCESS) {
  2025. switch(ZEND_NUM_ARGS())
  2026. {
  2027. case 5:
  2028. case 4:
  2029. switch (esc_len) {
  2030. case 0:
  2031. escape = PHP_CSV_NO_ESCAPE;
  2032. break;
  2033. case 1:
  2034. escape = (unsigned char) esc[0];
  2035. break;
  2036. default:
  2037. zend_argument_value_error(4, "must be empty or a single character");
  2038. RETURN_THROWS();
  2039. }
  2040. ZEND_FALLTHROUGH;
  2041. case 3:
  2042. if (e_len != 1) {
  2043. zend_argument_value_error(3, "must be a single character");
  2044. RETURN_THROWS();
  2045. }
  2046. enclosure = enclo[0];
  2047. ZEND_FALLTHROUGH;
  2048. case 2:
  2049. if (d_len != 1) {
  2050. zend_argument_value_error(2, "must be a single character");
  2051. RETURN_THROWS();
  2052. }
  2053. delimiter = delim[0];
  2054. ZEND_FALLTHROUGH;
  2055. case 1:
  2056. case 0:
  2057. break;
  2058. }
  2059. ret = php_fputcsv(intern->u.file.stream, fields, delimiter, enclosure, escape, eol);
  2060. if (ret < 0) {
  2061. RETURN_FALSE;
  2062. }
  2063. RETURN_LONG(ret);
  2064. }
  2065. }
  2066. /* }}} */
  2067. /* {{{ Set the delimiter, enclosure and escape character used in fgetcsv */
  2068. PHP_METHOD(SplFileObject, setCsvControl)
  2069. {
  2070. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  2071. char delimiter = ',', enclosure = '"';
  2072. int escape = (unsigned char) '\\';
  2073. char *delim = NULL, *enclo = NULL, *esc = NULL;
  2074. size_t d_len = 0, e_len = 0, esc_len = 0;
  2075. if (zend_parse_parameters(ZEND_NUM_ARGS(), "|sss", &delim, &d_len, &enclo, &e_len, &esc, &esc_len) == SUCCESS) {
  2076. switch(ZEND_NUM_ARGS())
  2077. {
  2078. case 3:
  2079. switch (esc_len) {
  2080. case 0:
  2081. escape = PHP_CSV_NO_ESCAPE;
  2082. break;
  2083. case 1:
  2084. escape = (unsigned char) esc[0];
  2085. break;
  2086. default:
  2087. zend_argument_value_error(3, "must be empty or a single character");
  2088. RETURN_THROWS();
  2089. }
  2090. ZEND_FALLTHROUGH;
  2091. case 2:
  2092. if (e_len != 1) {
  2093. zend_argument_value_error(2, "must be a single character");
  2094. RETURN_THROWS();
  2095. }
  2096. enclosure = enclo[0];
  2097. ZEND_FALLTHROUGH;
  2098. case 1:
  2099. if (d_len != 1) {
  2100. zend_argument_value_error(1, "must be a single character");
  2101. RETURN_THROWS();
  2102. }
  2103. delimiter = delim[0];
  2104. ZEND_FALLTHROUGH;
  2105. case 0:
  2106. break;
  2107. }
  2108. intern->u.file.delimiter = delimiter;
  2109. intern->u.file.enclosure = enclosure;
  2110. intern->u.file.escape = escape;
  2111. }
  2112. }
  2113. /* }}} */
  2114. /* {{{ Get the delimiter, enclosure and escape character used in fgetcsv */
  2115. PHP_METHOD(SplFileObject, getCsvControl)
  2116. {
  2117. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  2118. char delimiter[2], enclosure[2], escape[2];
  2119. array_init(return_value);
  2120. delimiter[0] = intern->u.file.delimiter;
  2121. delimiter[1] = '\0';
  2122. enclosure[0] = intern->u.file.enclosure;
  2123. enclosure[1] = '\0';
  2124. if (intern->u.file.escape == PHP_CSV_NO_ESCAPE) {
  2125. escape[0] = '\0';
  2126. } else {
  2127. escape[0] = (unsigned char) intern->u.file.escape;
  2128. escape[1] = '\0';
  2129. }
  2130. add_next_index_string(return_value, delimiter);
  2131. add_next_index_string(return_value, enclosure);
  2132. add_next_index_string(return_value, escape);
  2133. }
  2134. /* }}} */
  2135. /* {{{ Portable file locking */
  2136. PHP_METHOD(SplFileObject, flock)
  2137. {
  2138. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  2139. zval *wouldblock = NULL;
  2140. zend_long operation = 0;
  2141. if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|z", &operation, &wouldblock) == FAILURE) {
  2142. RETURN_THROWS();
  2143. }
  2144. CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
  2145. php_flock_common(intern->u.file.stream, operation, 1, wouldblock, return_value);
  2146. }
  2147. /* }}} */
  2148. /* {{{ Flush the file */
  2149. PHP_METHOD(SplFileObject, fflush)
  2150. {
  2151. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  2152. CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
  2153. RETURN_BOOL(!php_stream_flush(intern->u.file.stream));
  2154. } /* }}} */
  2155. /* {{{ Return current file position */
  2156. PHP_METHOD(SplFileObject, ftell)
  2157. {
  2158. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  2159. zend_long ret;
  2160. CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
  2161. ret = php_stream_tell(intern->u.file.stream);
  2162. if (ret == -1) {
  2163. RETURN_FALSE;
  2164. } else {
  2165. RETURN_LONG(ret);
  2166. }
  2167. } /* }}} */
  2168. /* {{{ Seek to a position */
  2169. PHP_METHOD(SplFileObject, fseek)
  2170. {
  2171. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  2172. zend_long pos, whence = SEEK_SET;
  2173. if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|l", &pos, &whence) == FAILURE) {
  2174. RETURN_THROWS();
  2175. }
  2176. CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
  2177. spl_filesystem_file_free_line(intern);
  2178. RETURN_LONG(php_stream_seek(intern->u.file.stream, pos, (int)whence));
  2179. } /* }}} */
  2180. /* {{{ Get a character from the file */
  2181. PHP_METHOD(SplFileObject, fgetc)
  2182. {
  2183. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  2184. char buf[2];
  2185. int result;
  2186. CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
  2187. spl_filesystem_file_free_line(intern);
  2188. result = php_stream_getc(intern->u.file.stream);
  2189. if (result == EOF) {
  2190. RETVAL_FALSE;
  2191. } else {
  2192. if (result == '\n') {
  2193. intern->u.file.current_line_num++;
  2194. }
  2195. buf[0] = result;
  2196. buf[1] = '\0';
  2197. RETURN_STRINGL(buf, 1);
  2198. }
  2199. } /* }}} */
  2200. /* {{{ Output all remaining data from a file pointer */
  2201. PHP_METHOD(SplFileObject, fpassthru)
  2202. {
  2203. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  2204. CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
  2205. RETURN_LONG(php_stream_passthru(intern->u.file.stream));
  2206. } /* }}} */
  2207. /* {{{ Implements a mostly ANSI compatible fscanf() */
  2208. PHP_METHOD(SplFileObject, fscanf)
  2209. {
  2210. int result, num_varargs = 0;
  2211. zend_string *format_str;
  2212. zval *varargs= NULL;
  2213. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  2214. if (zend_parse_parameters(ZEND_NUM_ARGS(), "S*", &format_str, &varargs, &num_varargs) == FAILURE) {
  2215. RETURN_THROWS();
  2216. }
  2217. CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
  2218. /* Get next line */
  2219. if (spl_filesystem_file_read(intern, 0) == FAILURE) {
  2220. RETURN_THROWS();
  2221. }
  2222. result = php_sscanf_internal(intern->u.file.current_line, ZSTR_VAL(format_str), num_varargs, varargs, 0, return_value);
  2223. if (SCAN_ERROR_WRONG_PARAM_COUNT == result) {
  2224. WRONG_PARAM_COUNT;
  2225. }
  2226. }
  2227. /* }}} */
  2228. /* {{{ Binary-safe file write */
  2229. PHP_METHOD(SplFileObject, fwrite)
  2230. {
  2231. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  2232. char *str;
  2233. size_t str_len;
  2234. zend_long length = 0;
  2235. ssize_t written;
  2236. if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &str, &str_len, &length) == FAILURE) {
  2237. RETURN_THROWS();
  2238. }
  2239. CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
  2240. if (ZEND_NUM_ARGS() > 1) {
  2241. if (length >= 0) {
  2242. str_len = MIN((size_t)length, str_len);
  2243. } else {
  2244. /* Negative length given, nothing to write */
  2245. str_len = 0;
  2246. }
  2247. }
  2248. if (!str_len) {
  2249. RETURN_LONG(0);
  2250. }
  2251. written = php_stream_write(intern->u.file.stream, str, str_len);
  2252. if (written < 0) {
  2253. RETURN_FALSE;
  2254. }
  2255. RETURN_LONG(written);
  2256. } /* }}} */
  2257. PHP_METHOD(SplFileObject, fread)
  2258. {
  2259. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  2260. zend_long length = 0;
  2261. zend_string *str;
  2262. if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &length) == FAILURE) {
  2263. RETURN_THROWS();
  2264. }
  2265. CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
  2266. if (length <= 0) {
  2267. zend_argument_value_error(1, "must be greater than 0");
  2268. RETURN_THROWS();
  2269. }
  2270. str = php_stream_read_to_str(intern->u.file.stream, length);
  2271. if (!str) {
  2272. RETURN_FALSE;
  2273. }
  2274. RETURN_STR(str);
  2275. }
  2276. /* {{{ Stat() on a filehandle */
  2277. PHP_METHOD(SplFileObject, fstat)
  2278. {
  2279. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  2280. if (zend_parse_parameters_none() == FAILURE) {
  2281. RETURN_THROWS();
  2282. }
  2283. CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
  2284. php_fstat(intern->u.file.stream, return_value);
  2285. }
  2286. /* }}} */
  2287. /* {{{ Truncate file to 'size' length */
  2288. PHP_METHOD(SplFileObject, ftruncate)
  2289. {
  2290. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  2291. zend_long size;
  2292. if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &size) == FAILURE) {
  2293. RETURN_THROWS();
  2294. }
  2295. CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
  2296. if (!php_stream_truncate_supported(intern->u.file.stream)) {
  2297. zend_throw_exception_ex(spl_ce_LogicException, 0, "Can't truncate file %s", ZSTR_VAL(intern->file_name));
  2298. RETURN_THROWS();
  2299. }
  2300. RETURN_BOOL(0 == php_stream_truncate_set_size(intern->u.file.stream, size));
  2301. } /* }}} */
  2302. /* {{{ Seek to specified line */
  2303. PHP_METHOD(SplFileObject, seek)
  2304. {
  2305. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  2306. zend_long line_pos, i;
  2307. if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &line_pos) == FAILURE) {
  2308. RETURN_THROWS();
  2309. }
  2310. CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
  2311. if (line_pos < 0) {
  2312. zend_argument_value_error(1, "must be greater than or equal to 0");
  2313. RETURN_THROWS();
  2314. }
  2315. spl_filesystem_file_rewind(ZEND_THIS, intern);
  2316. for (i = 0; i < line_pos; i++) {
  2317. if (spl_filesystem_file_read_line(ZEND_THIS, intern, 1) == FAILURE) {
  2318. return;
  2319. }
  2320. }
  2321. if (line_pos > 0) {
  2322. if (!SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_AHEAD)) {
  2323. intern->u.file.current_line_num++;
  2324. spl_filesystem_file_free_line(intern);
  2325. }
  2326. }
  2327. } /* }}} */
  2328. /* {{{ PHP_MINIT_FUNCTION(spl_directory) */
  2329. PHP_MINIT_FUNCTION(spl_directory)
  2330. {
  2331. spl_ce_SplFileInfo = register_class_SplFileInfo(zend_ce_stringable);
  2332. spl_ce_SplFileInfo->create_object = spl_filesystem_object_new;
  2333. memcpy(&spl_filesystem_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
  2334. spl_filesystem_object_handlers.offset = XtOffsetOf(spl_filesystem_object, std);
  2335. spl_filesystem_object_handlers.clone_obj = spl_filesystem_object_clone;
  2336. spl_filesystem_object_handlers.cast_object = spl_filesystem_object_cast;
  2337. spl_filesystem_object_handlers.dtor_obj = spl_filesystem_object_destroy_object;
  2338. spl_filesystem_object_handlers.free_obj = spl_filesystem_object_free_storage;
  2339. spl_ce_DirectoryIterator = register_class_DirectoryIterator(spl_ce_SplFileInfo, spl_ce_SeekableIterator);
  2340. spl_ce_DirectoryIterator->create_object = spl_filesystem_object_new;
  2341. spl_ce_DirectoryIterator->get_iterator = spl_filesystem_dir_get_iterator;
  2342. spl_ce_FilesystemIterator = register_class_FilesystemIterator(spl_ce_DirectoryIterator);
  2343. spl_ce_FilesystemIterator->create_object = spl_filesystem_object_new;
  2344. spl_ce_FilesystemIterator->get_iterator = spl_filesystem_tree_get_iterator;
  2345. REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "CURRENT_MODE_MASK", SPL_FILE_DIR_CURRENT_MODE_MASK);
  2346. REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "CURRENT_AS_PATHNAME", SPL_FILE_DIR_CURRENT_AS_PATHNAME);
  2347. REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "CURRENT_AS_FILEINFO", SPL_FILE_DIR_CURRENT_AS_FILEINFO);
  2348. REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "CURRENT_AS_SELF", SPL_FILE_DIR_CURRENT_AS_SELF);
  2349. REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "KEY_MODE_MASK", SPL_FILE_DIR_KEY_MODE_MASK);
  2350. REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "KEY_AS_PATHNAME", SPL_FILE_DIR_KEY_AS_PATHNAME);
  2351. REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "FOLLOW_SYMLINKS", SPL_FILE_DIR_FOLLOW_SYMLINKS);
  2352. REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "KEY_AS_FILENAME", SPL_FILE_DIR_KEY_AS_FILENAME);
  2353. REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "NEW_CURRENT_AND_KEY", SPL_FILE_DIR_KEY_AS_FILENAME|SPL_FILE_DIR_CURRENT_AS_FILEINFO);
  2354. REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "OTHER_MODE_MASK", SPL_FILE_DIR_OTHERS_MASK);
  2355. REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "SKIP_DOTS", SPL_FILE_DIR_SKIPDOTS);
  2356. REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "UNIX_PATHS", SPL_FILE_DIR_UNIXPATHS);
  2357. spl_ce_RecursiveDirectoryIterator = register_class_RecursiveDirectoryIterator(spl_ce_FilesystemIterator, spl_ce_RecursiveIterator);
  2358. spl_ce_RecursiveDirectoryIterator->create_object = spl_filesystem_object_new;
  2359. memcpy(&spl_filesystem_object_check_handlers, &spl_filesystem_object_handlers, sizeof(zend_object_handlers));
  2360. spl_filesystem_object_check_handlers.clone_obj = NULL;
  2361. spl_filesystem_object_check_handlers.get_method = spl_filesystem_object_get_method_check;
  2362. #ifdef HAVE_GLOB
  2363. spl_ce_GlobIterator = register_class_GlobIterator(spl_ce_FilesystemIterator, zend_ce_countable);
  2364. spl_ce_GlobIterator->create_object = spl_filesystem_object_new_check;
  2365. #endif
  2366. spl_ce_SplFileObject = register_class_SplFileObject(spl_ce_SplFileInfo, spl_ce_RecursiveIterator, spl_ce_SeekableIterator);
  2367. spl_ce_SplFileObject->create_object = spl_filesystem_object_new_check;
  2368. REGISTER_SPL_CLASS_CONST_LONG(SplFileObject, "DROP_NEW_LINE", SPL_FILE_OBJECT_DROP_NEW_LINE);
  2369. REGISTER_SPL_CLASS_CONST_LONG(SplFileObject, "READ_AHEAD", SPL_FILE_OBJECT_READ_AHEAD);
  2370. REGISTER_SPL_CLASS_CONST_LONG(SplFileObject, "SKIP_EMPTY", SPL_FILE_OBJECT_SKIP_EMPTY);
  2371. REGISTER_SPL_CLASS_CONST_LONG(SplFileObject, "READ_CSV", SPL_FILE_OBJECT_READ_CSV);
  2372. spl_ce_SplTempFileObject = register_class_SplTempFileObject(spl_ce_SplFileObject);
  2373. spl_ce_SplTempFileObject->create_object = spl_filesystem_object_new_check;
  2374. return SUCCESS;
  2375. }
  2376. /* }}} */