├── .gitignore ├── LICENSE ├── README.MD ├── TODO.MD └── src ├── bamcompile php ├── bamcompile.php ├── stub.exe └── upx.exe ├── php_hacks ├── extra_modules │ ├── MemoryModule.c │ └── MemoryModule.h └── php_src │ ├── ext │ └── standard │ │ ├── dl.c │ │ └── dl.h │ └── main │ ├── php_ini.c │ └── streams.c └── stub php ├── bambalam_getini.php └── bambalam_init.php /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea/ 2 | /.nbproject/ 3 | /.php_original/ 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | 341 | -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | # Bamcompile 2 | Bambalam PHP EXE Compiler/Embedder 3 | 4 | > This project was abandoned long time ago by it's original author 5 | > Anders Hammar. Latest official update was on 28th of August 2006. My 6 | > plans are to implement PHP5 support instead of obsolete PHP4 and 7 | > improve this software as well. 8 | > 9 | > This software deserves a new chance. 10 | > I have tried many PHP "compilers" and since only Bamcompiler was great, despite the fact that it is completely obsolete. 11 | > Although I don't have many experience with compiling, neither I know how everything was put together, I will give it a try. 12 | > Help is very welcome!!! 13 | 14 | 1. **What is it?** 15 | Bambalam PHP EXE Compiler/Embedder is a free command line tool to convert PHP applications to standalone Windows .exe applications. The exe files produced are totally standalone, no need for php dlls etc. The php code is encoded using the [Turck MMCache Encode library](http://turck-mmcache.sourceforge.net/) so it's a perfect solution if you want to distribute your application while protecting your source code. The converter is also suitable for producing .exe files for windowed PHP applications (created using for example the [WinBinder library](http://www.winbinder.com/)). It's also good for making stand-alone PHP Socket servers/clients (using the php_sockets.dll extension). 16 | It's NOT really a compiler in the sense that it doesn't produce native machine code from PHP sources, but it works! 17 | The tool is free and open source. However, if you use it commercially (ie to make money in some way) you should make a [donation](http://sourceforge.net/donate/index.php?group_id=169996) to keep the project alive! 18 | 19 | 2. **How does it work?** 20 | The converter embeds encoded PHP source files as resources in a generic statically compiled PHP launcher executable. It also has an option to compress the final exe using the [UPX executable compressor](http://upx.sourceforge.net/). Simple console applications end up with an executable at a size of 500-600kb. 21 | 3. **Does "compiled" PHP applications run faster?** 22 | Theoretically it should. Having libraries linked statically and encoding files (Turck MMCache encodes PHP sources as PHP bytecode, I think) should contribute to faster applications. But I haven't done any decent tests on it. 23 | 24 | 4. **What about PHP applications with more than one source file?** 25 | No problem, the converter is able to embed a whole project directory. Or, if you want, you can create a bamcompile project file (.bcp) and embed files from all over the place. 26 | 27 | 5. **What about accessing the embedded files from php?** 28 | You can access the embedded files just as you're used to. The PHP runtime used has been modified so that when you're accessing a file it first tries to access it the usual way (by looking in the path outside the .exe) and if the files aren't found there it looks for it in the embedded filelist. 29 | 30 | 6. **So the INCLUDE statement works just as it should?** 31 | Yes, as long as you include stuff using relative paths. 32 | 33 | 7. **What PHP version is supported?** 34 | Currently, the converter uses a PHP runtime based on PHP 4.4.4 35 | Plans are to implement PHP5 and above. 36 | 37 | 8. **What about PHP 5 support?** 38 | I haven't got around to it, but I probably will! But PHP 4.4.4 works in most cases, and the PHP 4 runtimes produces alot smaller standalone exe files than PHP 5 would do. PHP 5 is a bitch to build on windows (well, it's easy to build the standard builds, but other than that..) But as I said, just wait for it. 39 | 40 | 41 | 9. **What libraries / extensions are included?** 42 | As of version 1.2, php libraries (or extensions) now can be embedded as needed. So, for example, if you're making an application that uses the gd extension, use the -e:php_gd2.dll option and you'll be fine. You can also use the EXTENSION command when working with bamcompile project files. You still have to have access to the php extension dll files when embedding of course, they are shipped together with the PHP distribution. But once you have compiled your exe, that's the only file you have to distribute! 43 | Note however that some extensions use other system dlls which needs to be shipped together with your compiled exe to make it work. 44 | Some examples: 45 | ``` 46 | php_curl.dll needs libeay32.dll and ssleay32.dll 47 | php_mssql.dll needs ntwdblib.dll 48 | php_fribidi.dll needs fribidi.dll 49 | php_fdf.dll needs FDFTK.dll 50 | php_ifx.dll needs isqlt09a.dll 51 | php_mhash.dll needs ibmhash.dll 52 | php_msql.dll needs mSQL.dll 53 | ``` 54 | But most of them, such as GD, Sockets, Winbinder and Sqlite don't need any system dlls and they embed just fine. 55 | 56 | The following libraries are included statically: 57 | ``` 58 | Turck 59 | MMCache 60 | bcmath 61 | calendar 62 | com 63 | ctype 64 | ftp 65 | mysql 66 | odbc 67 | pcre 68 | win32std 69 | xml zlib 70 | ``` 71 | 72 | 10. **Can I add a custom Icon to my exe?** 73 | Yes, use the -i:icon.ico command line option or the ICON project file command. 74 | 11. **What about PHP.INI? Can I embed that as well?** 75 | Yes, just include the php.ini in the root of your project. However, if you want to use extensions, use the internal extension loader instead. Older versions of Bamcompile used the embedded php.ini to load extensions but it was messy and honestly didn't work that well. You can still embed php.ini to set ini specific settings. 76 | 77 | 12. **What is the format of Bamcompile Project files?** 78 | A project file has the extension .bcp and is built up using simple commands, one on each line: 79 | 80 | ``` 81 | MAINFILE mainfile.php 82 | ``` 83 | Sets the mainfile to whatever mainfile you want to use. 84 | 85 | ``` 86 | OUTFILE outfile.exe 87 | ``` 88 | Sets the output file exe name. Optional. 89 | 90 | ```ICON icon.ico``` 91 | Sets an icon for the output exe file. Optional. 92 | 93 | ``` 94 | COMPRESS 95 | ``` 96 | Compresses final exe file with UPX 97 | 98 | ``` 99 | DONTENCODE 100 | ``` 101 | Do not encode php files 102 | ``` 103 | WINDOWED 104 | ``` 105 | Windowed application, removes the "dos box" otherwise shown 106 | ``` 107 | EMBED directory/file.php 108 | EMBED whole_directory 109 | EMBED directory/*.png 110 | ``` 111 | Used to embed files. You can embed single files, directories or files using a filters. Directories are embedded recursivly 112 | 113 | ``` 114 | DESTINATION destination_path/ 115 | ``` 116 | Sets the destination path in the embedded filesystem. Use the destination command before an embed command to change where the embedded files end up. The default destination path is, of course, the root /. 117 | 118 | ``` 119 | EXTENSION path_to/extension.dll 120 | ``` 121 | Adds a PHP extension to the internal extension loader. The extension will be embedded and loaded from memory. 122 | 123 | 13. **License** 124 | Take a look at file **LICENSE** 125 | 126 | 127 | **Usage:** 128 | ``` 129 | bamcompile [-options] infile.php [outfile.exe] 130 | bamcompile [-options] project_directory mainfile.php [outfile.exe] 131 | bamcompile projectfile.bcp 132 | ``` 133 | 134 | **Options:** 135 | ``` 136 | -w Hide console window for windowed applications 137 | -c Compress output exe (using UPX) 138 | -d Do not encode PHP files 139 | -e:extension.dll Embed and use PHP extension 140 | -i:icon.ico Add icon to exe 141 | ``` 142 | 143 | Revision history: 144 | - 145 | 146 | **1.21 2006-08-28:** 147 | + Fixed an issue with apps using extensions crashing if php4ts.dll was in the system path 148 | 149 | **1.2 2006-08-24:** 150 | + Added an extension loader - extension dll's can now be embedded 151 | + Added a project file feature 152 | + Added support for exe icons 153 | + UPX is now embedded, it's no longer needed in the system path 154 | + Added some examples of PHP applications 155 | + Upgraded to PHP 4.4.4 156 | + Fixed some compatibility issues when running on a system with PHP installed 157 | + Lots of minor bugfixes 158 | 159 | **1.1 2006-06-09:** 160 | + Added the php_sockets extension to the static build 161 | + minor bugfixes 162 | -------------------------------------------------------------------------------- /TODO.MD: -------------------------------------------------------------------------------- 1 | * Add support for PHP5+ 2 | -------------------------------------------------------------------------------- /src/bamcompile php/bamcompile.php: -------------------------------------------------------------------------------- 1 | read())) { 10 | if ( ! ($entry == '.') & ! ($entry == '..')) { 11 | if (is_dir($dir . '/' . $entry)) { 12 | get_all_files($dir . '/' . $entry, $subpath . $entry . '/'); 13 | } else { 14 | $includefiles[] = array($sourcepath . $subpath . $entry, $destpath . $subpath . $entry); 15 | } 16 | } 17 | } 18 | } 19 | 20 | print "\nBambalam PHP EXE Compiler/Embedder 1.21\n\n"; 21 | 22 | if ($argc == 1) { 23 | print "Converts PHP applications to standalone .exe 24 | Created by Anders Hammar (c) 2006 Bambalam - www.bambalam.se/bamcompile 25 | 26 | Usage: 27 | bamcompile [-options] infile.php [outfile.exe] 28 | bamcompile [-options] project_directory mainfile.php [outfile.exe] 29 | bamcompile projectfile.bcp 30 | 31 | Options: 32 | -w Hide console window for windowed applications 33 | -c Compress output exe (using UPX) 34 | -d Do not encode PHP files 35 | -e:extension.dll Embed and use PHP extension 36 | -i:icon.ico Add icon to exe 37 | "; 38 | exit; 39 | } 40 | 41 | $option_windowed = false; 42 | $option_compress = false; 43 | $option_noencode = false; 44 | $option_minimal = false; 45 | 46 | $mainfile = ""; 47 | $includefiles = array(); 48 | $outfile = ""; 49 | $projectdir = ""; 50 | $extensions = array(); 51 | $projectfile = ""; 52 | $iconfile = ""; 53 | 54 | // process arguments 55 | 56 | while (list($nr, $val) = each($argv)) { 57 | if ($nr > 0) { 58 | $val = strtolower($val); 59 | if ($val == '-w') { 60 | $option_windowed = true; 61 | } else if ($val == '-c') { 62 | $option_compress = true; 63 | } else if ($val == '-d') { 64 | $option_noencode = true; 65 | } else if (strpos($val, '.php') > -1) { 66 | $mainfile = $val; 67 | } else if (strpos($val, '.exe') > -1) { 68 | $outfile = $val; 69 | } else if (strpos($val, '.bcp') > -1) { 70 | $projectfile = $val; 71 | } else if (substr($val, 0, 3) == '-e:') { 72 | $extensions[] = substr($val, 3); 73 | } else if (substr($val, 0, 3) == '-i:') { 74 | $iconfile = substr($val, 3); 75 | } else if (is_dir($val)) { 76 | $projectdir = $val; 77 | } 78 | } 79 | } 80 | 81 | $sourcepath = ""; 82 | $destpath = ""; 83 | 84 | if ($projectfile) { 85 | if ( ! file_exists($projectfile)) { 86 | print "Problem: Project file $projectfile does not exist!\n"; 87 | exit; 88 | } 89 | $projectdir = ""; 90 | print "Using project file: $projectfile\n"; 91 | $projectdata = file($projectfile); 92 | while (list(, $row) = each($projectdata)) { 93 | $row = strtolower(trim($row)); 94 | if (substr($row, 0, 5) == 'embed') { 95 | $embedpath = trim(substr($row, 5)); 96 | if (is_dir($embedpath)) { 97 | $sourcepath = str_replace('/', '\\', $embedpath); 98 | if (substr($sourcepath, strlen($sourcepath) - 1, 1) != '\\') { 99 | $sourcepath .= '\\'; 100 | } 101 | get_all_files($embedpath); 102 | } else { 103 | if (file_exists($embedpath)) { 104 | $includefiles[] = array($embedpath, $destpath . basename($embedpath)); 105 | } 106 | $filter = basename($embedpath); 107 | if (substr($filter, 0, 2) == '*.') { 108 | $filterdir = dirname($embedpath); 109 | $filterext = substr($filter, 2); 110 | $d = dir($filterdir); 111 | while (false !== ($entry = $d->read())) { 112 | if ( ! ($entry == '.') & ! ($entry == '..') & (strpos($entry, $filterext) > -1)) { 113 | $includefiles[] = array($filterdir . '/' . $entry, $destpath . $entry); 114 | } 115 | } 116 | } 117 | } 118 | } 119 | if (substr($row, 0, 11) == 'destination') { 120 | $destpath = trim(substr($row, 11)); 121 | $destpath = str_replace('\\', '/', $destpath); 122 | if (substr($destpath, strlen($destpath) - 1, 1) != '/') { 123 | $destpath .= '/'; 124 | } 125 | if ($destpath == '/') { 126 | $destpath = ""; 127 | } 128 | } 129 | if (substr($row, 0, 9) == 'extension') { 130 | $extensions[] = trim(substr($row, 9)); 131 | } 132 | if (substr($row, 0, 8) == 'mainfile') { 133 | $mainfile = trim(substr($row, 8)); 134 | } 135 | if (substr($row, 0, 7) == 'outfile') { 136 | $outfile = trim(substr($row, 7)); 137 | } 138 | if (substr($row, 0, 4) == 'icon') { 139 | $iconfile = trim(substr($row, 4)); 140 | } 141 | if (substr($row, 0, 8) == 'compress') { 142 | $option_compress = true; 143 | } 144 | if (substr($row, 0, 10) == 'dontencode') { 145 | $option_noencode = true; 146 | } 147 | if (substr($row, 0, 8) == 'windowed') { 148 | $option_windowed = true; 149 | } 150 | } 151 | } 152 | 153 | if ($mainfile == "" & is_dir($projectdir)) { 154 | print "Problem: You must specify a main PHP file in your project directory!\n"; 155 | exit; 156 | } 157 | 158 | if ($mainfile == "") { 159 | print "Problem: You must at least specify a PHP file to compile!\n"; 160 | exit; 161 | } 162 | 163 | if ($mainfile & $projectfile) { 164 | reset($includefiles); 165 | $found = false; 166 | while (list(, $file) = each($includefiles)) { 167 | if (basename($file[0]) == $mainfile) { 168 | $found = true; 169 | } 170 | } 171 | if ( ! $found) { 172 | print "Problem: Main file $mainfile not found!\n"; 173 | exit; 174 | } 175 | reset($includefiles); 176 | } 177 | 178 | if ($outfile == "") { 179 | $outfile = substr($mainfile, 0, strpos($mainfile, '.php')) . '.exe'; 180 | } 181 | 182 | if ($option_windowed) { 183 | print "Windowed application\n"; 184 | } 185 | if ($option_compress) { 186 | print "Compress\n"; 187 | } 188 | if ($option_noencode) { 189 | print "Do not encode\n"; 190 | } 191 | if ($mainfile) { 192 | print "Mainfile: $mainfile\n"; 193 | } 194 | if ($outfile) { 195 | print "Outfile: $outfile\n"; 196 | } 197 | if ($iconfile) { 198 | print "Icon: $iconfile\n"; 199 | } 200 | if ($projectdir) { 201 | print "Project dir: $projectdir\n"; 202 | } 203 | 204 | if ($projectdir) { 205 | if ( ! is_dir($projectdir)) { 206 | print "Problem: Project directory not found\n"; 207 | exit; 208 | } 209 | if ( ! file_exists($projectdir . '/' . $mainfile)) { 210 | print "Problem: Main php not found at $projectdir/$mainfile\n"; 211 | exit; 212 | } 213 | $sourcepath = str_replace('/', '\\', $projectdir); 214 | if (substr($sourcepath, strlen($sourcepath) - 1, 1) != '\\') { 215 | $sourcepath .= '\\'; 216 | } 217 | get_all_files($projectdir); 218 | } else { 219 | if ($projectfile == "") { 220 | if ( ! file_exists($mainfile)) { 221 | print "Problem: Main file $mainfile not found!\n"; 222 | exit; 223 | } 224 | $includefiles[] = array($mainfile, $mainfile); 225 | } 226 | } 227 | 228 | // check for embedded extensions, they don't need to be embedded twice 229 | reset($includefiles); 230 | while (list($nr, $file) = each($includefiles)) { 231 | reset($extensions); 232 | while (list(, $ext) = each($extensions)) { 233 | if (basename($file[0]) == basename($ext)) { 234 | $includefiles[$nr] = array("", ""); 235 | } 236 | } 237 | } 238 | reset($includefiles); 239 | reset($extensions); 240 | 241 | // check for embedded icon 242 | if ($iconfile) { 243 | reset($includefiles); 244 | while (list($nr, $file) = each($includefiles)) { 245 | if (basename($file[0]) == basename($iconfile)) { 246 | $includefiles[$nr] = array("", ""); 247 | } 248 | } 249 | reset($includefiles); 250 | } 251 | 252 | // create, compile and embed! 253 | 254 | $stub = file_get_contents("stub.exe"); 255 | 256 | // make windowed application if wanted 257 | 258 | if ($option_windowed) { 259 | $stub[372] = chr(2); 260 | } 261 | 262 | @$f = fopen($outfile, "w"); 263 | if ( ! $f) { 264 | print "Problem: Could not write to $outfile - maybe it's running?\n"; 265 | exit; 266 | } 267 | fwrite($f, $stub); 268 | fclose($f); 269 | 270 | print "\n"; 271 | 272 | while (list(, $file) = each($includefiles)) { 273 | $sourcefile = $file[0]; 274 | $file = $file[1]; 275 | if ($file != "") { 276 | $embedfile = str_replace('/', '\\', $file); 277 | 278 | if (strpos($file, '.php') > -1 & ! $option_noencode) { 279 | print "Encoding and embedding $file\n"; 280 | $encdata = mmcache_encode($sourcefile); 281 | $data = ""; 282 | res_set($outfile, "PHP", $embedfile, $data); 283 | } else { 284 | print "Embedding $file\n"; 285 | $data = file_get_contents($sourcefile); 286 | res_set($outfile, "PHP", $embedfile, $data); 287 | } 288 | } 289 | } 290 | 291 | res_set($outfile, "PHP", "MAIN", $mainfile); 292 | 293 | $extension_loadlist = array(); 294 | 295 | if (count($extensions) > 0) { 296 | while (list(, $file) = each($extensions)) { 297 | $extension_file = $file; 298 | if ( ! file_exists($extension_file)) { 299 | $extension_file = $path . $file; 300 | } 301 | if ( ! file_exists($extension_file)) { 302 | print "Extension $file not found\n"; 303 | } else { 304 | print "Embedding " . basename($file) . " and adding it to extension loader\n"; 305 | $embedfile = basename($extension_file); 306 | $data = file_get_contents($extension_file); 307 | res_set($outfile, "PHP", $embedfile, $data); 308 | $extension_loadlist[] = $embedfile; 309 | } 310 | } 311 | } 312 | 313 | if (count($extensions) > 0) { 314 | res_set($outfile, "PHP", "EXTENSIONS", implode(';', $extension_loadlist)); 315 | } 316 | 317 | if (file_exists($iconfile)) { 318 | $icondata = file_get_contents($iconfile); 319 | $offset = 4; 320 | $icon_count = unpack("S", substr($icondata, $offset, 2)); 321 | $icon_count = $icon_count[1]; 322 | $offset += 2; 323 | $icons = array(); 324 | for ($i = 0; $i < $icon_count; $i++) { 325 | $icon = array(); 326 | 327 | $val = unpack("C", substr($icondata, $offset, 1)); 328 | $icon[width] = $val[1]; 329 | $offset++; 330 | 331 | $val = unpack("C", substr($icondata, $offset, 1)); 332 | $icon[height] = $val[1]; 333 | $offset++; 334 | 335 | $val = unpack("C", substr($icondata, $offset, 1)); 336 | $icon[colors] = $val[1]; 337 | $offset += 2; 338 | 339 | $val = unpack("S", substr($icondata, $offset, 2)); 340 | $icon[planes] = $val[1]; 341 | $offset += 2; 342 | 343 | $val = unpack("S", substr($icondata, $offset, 2)); 344 | $icon[bitcount] = $val[1]; 345 | $offset += 2; 346 | 347 | $val = unpack("L", substr($icondata, $offset, 4)); 348 | $icon[size] = $val[1]; 349 | $offset += 4; 350 | 351 | $val = unpack("L", substr($icondata, $offset, 4)); 352 | $icon[offset] = $val[1]; 353 | $offset += 4; 354 | 355 | $icons[] = $icon; 356 | } 357 | for ($i = 0; $i < count($icons); $i++) { 358 | $data = substr($icondata, $icons[$i][offset], $icons[$i][size]); 359 | $icons[$i][data] = $data; 360 | } 361 | 362 | $icon_group = ""; 363 | $icon_group .= pack("S", 0); 364 | $icon_group .= pack("S", 1); 365 | $icon_group .= pack("S", $icon_count); 366 | for ($i = 0; $i < $icon_count; $i++) { 367 | $icon_group .= pack("C", $icons[$i][width]); 368 | $icon_group .= pack("C", $icons[$i][height]); 369 | $icon_group .= pack("C", $icons[$i][colors]); 370 | $icon_group .= pack("C", 0); // "RESERVED" 371 | $icon_group .= pack("S", $icons[$i][planes]); 372 | $icon_group .= pack("S", $icons[$i][bitcount]); 373 | $icon_group .= pack("L", $icons[$i][size]); 374 | $icon_group .= pack("S", $i + 1); 375 | } 376 | 377 | print "Updating icon..."; 378 | res_set($outfile, "RT_GROUP_ICON", "#1", $icon_group); 379 | for ($i = 0; $i < $icon_count; $i++) { 380 | $worked = res_set($outfile, RT_ICON, "#" . ($i + 1), $icons[$i][data]); 381 | } 382 | print "done\n"; 383 | } 384 | 385 | if ($option_compress) { 386 | print "Compressing final exe..\n"; 387 | $upx = file_get_contents("upx.exe"); 388 | $f = fopen("bamcompile_upx.exe", "w"); 389 | fwrite($f, $upx); 390 | fclose($f); 391 | 392 | $stub = file_get_contents("stub.exe"); 393 | exec("bamcompile_upx -9 $outfile", $out, $ret); 394 | if ($ret > 0) { 395 | print "Compression failed! Is upx.exe available?\n"; 396 | } else { 397 | print "Compression done\n"; 398 | } 399 | unlink("bamcompile_upx.exe"); 400 | } 401 | 402 | print "\n$outfile created successfully!\n"; 403 | -------------------------------------------------------------------------------- /src/bamcompile php/stub.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xZero707/Bamcompile/a69b73d569f7459dc3fc44bd262bf59a8755a7a4/src/bamcompile php/stub.exe -------------------------------------------------------------------------------- /src/bamcompile php/upx.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xZero707/Bamcompile/a69b73d569f7459dc3fc44bd262bf59a8755a7a4/src/bamcompile php/upx.exe -------------------------------------------------------------------------------- /src/php_hacks/extra_modules/MemoryModule.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Memory DLL loading code 3 | * Version 0.0.2 with additions from Thomas Heller 4 | * 5 | * Copyright (c) 2004-2005 by Joachim Bauch / mail@joachim-bauch.de 6 | * http://www.joachim-bauch.de 7 | * 8 | * The contents of this file are subject to the Mozilla Public License Version 9 | * 1.1 (the "License"); you may not use this file except in compliance with 10 | * the License. You may obtain a copy of the License at 11 | * http://www.mozilla.org/MPL/ 12 | * 13 | * Software distributed under the License is distributed on an "AS IS" basis, 14 | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 15 | * for the specific language governing rights and limitations under the 16 | * License. 17 | * 18 | * The Original Code is MemoryModule.c 19 | * 20 | * The Initial Developer of the Original Code is Joachim Bauch. 21 | * 22 | * Portions created by Joachim Bauch are Copyright (C) 2004-2005 23 | * Joachim Bauch. All Rights Reserved. 24 | * 25 | * Portions Copyright (C) 2005 Thomas Heller. 26 | * 27 | */ 28 | 29 | // disable warnings about pointer <-> DWORD conversions 30 | #pragma warning( disable : 4311 4312 ) 31 | 32 | #include 33 | #include 34 | #if DEBUG_OUTPUT 35 | #include 36 | #endif 37 | 38 | #include "MemoryModule.h" 39 | 40 | /* 41 | XXX We need to protect at least walking the 'loaded' linked list with a lock! 42 | */ 43 | 44 | /******************************************************************/ 45 | FINDPROC findproc; 46 | void *findproc_data; 47 | 48 | struct NAME_TABLE { 49 | char *name; 50 | DWORD ordinal; 51 | }; 52 | 53 | typedef struct tagMEMORYMODULE { 54 | PIMAGE_NT_HEADERS headers; 55 | unsigned char *codeBase; 56 | HMODULE *modules; 57 | int numModules; 58 | int initialized; 59 | 60 | struct NAME_TABLE *name_table; 61 | 62 | char *name; 63 | int refcount; 64 | struct tagMEMORYMODULE *next, *prev; 65 | } MEMORYMODULE, *PMEMORYMODULE; 66 | 67 | typedef BOOL (WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved); 68 | 69 | #define GET_HEADER_DICTIONARY(module, idx) &(module)->headers->OptionalHeader.DataDirectory[idx] 70 | 71 | MEMORYMODULE *loaded; /* linked list of loaded memory modules */ 72 | 73 | /* private - insert a loaded library in a linked list */ 74 | static void _Register(char *name, MEMORYMODULE *module) 75 | { 76 | module->next = loaded; 77 | if (loaded) 78 | loaded->prev = module; 79 | module->prev = NULL; 80 | loaded = module; 81 | } 82 | 83 | /* private - remove a loaded library from a linked list */ 84 | static void _Unregister(MEMORYMODULE *module) 85 | { 86 | free(module->name); 87 | if (module->prev) 88 | module->prev->next = module->next; 89 | if (module->next) 90 | module->next->prev = module->prev; 91 | if (module == loaded) 92 | loaded = module->next; 93 | } 94 | 95 | /* public - replacement for GetModuleHandle() */ 96 | HMODULE MyGetModuleHandle(LPCTSTR lpModuleName) 97 | { 98 | MEMORYMODULE *p = loaded; 99 | while (p) { 100 | // If already loaded, only increment the reference count 101 | if (0 == stricmp(lpModuleName, p->name)) { 102 | return (HMODULE)p; 103 | } 104 | p = p->next; 105 | } 106 | return GetModuleHandle(lpModuleName); 107 | } 108 | 109 | /* public - replacement for LoadLibrary, but searches FIRST for memory 110 | libraries, then for normal libraries. So, it will load libraries AS memory 111 | module if they are found by findproc(). 112 | */ 113 | HMODULE MyLoadLibrary(char *lpFileName) 114 | { 115 | MEMORYMODULE *p = loaded; 116 | HMODULE hMod; 117 | 118 | while (p) { 119 | // If already loaded, only increment the reference count 120 | if (0 == stricmp(lpFileName, p->name)) { 121 | p->refcount++; 122 | return (HMODULE)p; 123 | } 124 | p = p->next; 125 | } 126 | if (findproc) { 127 | void *pdata = findproc(lpFileName, findproc_data); 128 | if (pdata) { 129 | hMod = MemoryLoadLibrary(lpFileName, pdata); 130 | free(p); 131 | return hMod; 132 | } 133 | } 134 | hMod = LoadLibrary(lpFileName); 135 | return hMod; 136 | } 137 | 138 | /* public - replacement for GetProcAddress() */ 139 | FARPROC MyGetProcAddress(HMODULE hModule, LPCSTR lpProcName) 140 | { 141 | MEMORYMODULE *p = loaded; 142 | while (p) { 143 | if ((HMODULE)p == hModule) 144 | return MemoryGetProcAddress(p, lpProcName); 145 | p = p->next; 146 | } 147 | return GetProcAddress(hModule, lpProcName); 148 | } 149 | 150 | /* public - replacement for FreeLibrary() */ 151 | BOOL MyFreeLibrary(HMODULE hModule) 152 | { 153 | MEMORYMODULE *p = loaded; 154 | while (p) { 155 | if ((HMODULE)p == hModule) { 156 | if (--p->refcount == 0) { 157 | _Unregister(p); 158 | MemoryFreeLibrary(p); 159 | } 160 | return TRUE; 161 | } 162 | p = p->next; 163 | } 164 | return FreeLibrary(hModule); 165 | } 166 | 167 | #if DEBUG_OUTPUT 168 | static void 169 | OutputLastError(const char *msg) 170 | { 171 | LPVOID tmp; 172 | char *tmpmsg; 173 | FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 174 | NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&tmp, 0, NULL); 175 | tmpmsg = (char *)LocalAlloc(LPTR, strlen(msg) + strlen(tmp) + 3); 176 | sprintf(tmpmsg, "%s: %s", msg, tmp); 177 | OutputDebugString(tmpmsg); 178 | LocalFree(tmpmsg); 179 | LocalFree(tmp); 180 | } 181 | #endif 182 | 183 | /* 184 | static int dprintf(char *fmt, ...) 185 | { 186 | char Buffer[4096]; 187 | va_list marker; 188 | int result; 189 | 190 | va_start(marker, fmt); 191 | result = vsprintf(Buffer, fmt, marker); 192 | OutputDebugString(Buffer); 193 | return result; 194 | } 195 | */ 196 | 197 | static void 198 | CopySections(const unsigned char *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMODULE module) 199 | { 200 | int i, size; 201 | unsigned char *codeBase = module->codeBase; 202 | unsigned char *dest; 203 | PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers); 204 | for (i=0; iheaders->FileHeader.NumberOfSections; i++, section++) 205 | { 206 | if (section->SizeOfRawData == 0) 207 | { 208 | // section doesn't contain data in the dll itself, but may define 209 | // uninitialized data 210 | size = old_headers->OptionalHeader.SectionAlignment; 211 | if (size > 0) 212 | { 213 | dest = (unsigned char *)VirtualAlloc(codeBase + section->VirtualAddress, 214 | size, 215 | MEM_COMMIT, 216 | PAGE_READWRITE); 217 | 218 | section->Misc.PhysicalAddress = (DWORD)dest; 219 | memset(dest, 0, size); 220 | } 221 | 222 | // section is empty 223 | continue; 224 | } 225 | 226 | // commit memory block and copy data from dll 227 | dest = (unsigned char *)VirtualAlloc(codeBase + section->VirtualAddress, 228 | section->SizeOfRawData, 229 | MEM_COMMIT, 230 | PAGE_READWRITE); 231 | memcpy(dest, data + section->PointerToRawData, section->SizeOfRawData); 232 | section->Misc.PhysicalAddress = (DWORD)dest; 233 | } 234 | } 235 | 236 | // Protection flags for memory pages (Executable, Readable, Writeable) 237 | static int ProtectionFlags[2][2][2] = { 238 | { 239 | // not executable 240 | {PAGE_NOACCESS, PAGE_WRITECOPY}, 241 | {PAGE_READONLY, PAGE_READWRITE}, 242 | }, { 243 | // executable 244 | {PAGE_EXECUTE, PAGE_EXECUTE_WRITECOPY}, 245 | {PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE}, 246 | }, 247 | }; 248 | 249 | static void 250 | FinalizeSections(PMEMORYMODULE module) 251 | { 252 | int i; 253 | PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers); 254 | 255 | // loop through all sections and change access flags 256 | for (i=0; iheaders->FileHeader.NumberOfSections; i++, section++) 257 | { 258 | DWORD protect, oldProtect, size; 259 | int executable = (section->Characteristics & IMAGE_SCN_MEM_EXECUTE) != 0; 260 | int readable = (section->Characteristics & IMAGE_SCN_MEM_READ) != 0; 261 | int writeable = (section->Characteristics & IMAGE_SCN_MEM_WRITE) != 0; 262 | 263 | if (section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) 264 | { 265 | // section is not needed any more and can safely be freed 266 | VirtualFree((LPVOID)section->Misc.PhysicalAddress, section->SizeOfRawData, MEM_DECOMMIT); 267 | continue; 268 | } 269 | 270 | // determine protection flags based on characteristics 271 | protect = ProtectionFlags[executable][readable][writeable]; 272 | if (section->Characteristics & IMAGE_SCN_MEM_NOT_CACHED) 273 | protect |= PAGE_NOCACHE; 274 | 275 | // determine size of region 276 | size = section->SizeOfRawData; 277 | if (size == 0) 278 | { 279 | if (section->Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) 280 | size = module->headers->OptionalHeader.SizeOfInitializedData; 281 | else if (section->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) 282 | size = module->headers->OptionalHeader.SizeOfUninitializedData; 283 | } 284 | 285 | if (size > 0) 286 | { 287 | // change memory access flags 288 | if (VirtualProtect((LPVOID)section->Misc.PhysicalAddress, section->SizeOfRawData, protect, &oldProtect) == 0) 289 | #if DEBUG_OUTPUT 290 | OutputLastError("Error protecting memory page") 291 | #endif 292 | ; 293 | } 294 | } 295 | } 296 | 297 | static void 298 | PerformBaseRelocation(PMEMORYMODULE module, DWORD delta) 299 | { 300 | DWORD i; 301 | unsigned char *codeBase = module->codeBase; 302 | 303 | PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_BASERELOC); 304 | if (directory->Size > 0) 305 | { 306 | PIMAGE_BASE_RELOCATION relocation = (PIMAGE_BASE_RELOCATION)(codeBase + directory->VirtualAddress); 307 | for (; relocation->VirtualAddress > 0; ) 308 | { 309 | unsigned char *dest = (unsigned char *)(codeBase + relocation->VirtualAddress); 310 | unsigned short *relInfo = (unsigned short *)((unsigned char *)relocation + IMAGE_SIZEOF_BASE_RELOCATION); 311 | for (i=0; i<((relocation->SizeOfBlock-IMAGE_SIZEOF_BASE_RELOCATION) / 2); i++, relInfo++) 312 | { 313 | DWORD *patchAddrHL; 314 | int type, offset; 315 | 316 | // the upper 4 bits define the type of relocation 317 | type = *relInfo >> 12; 318 | // the lower 12 bits define the offset 319 | offset = *relInfo & 0xfff; 320 | 321 | switch (type) 322 | { 323 | case IMAGE_REL_BASED_ABSOLUTE: 324 | // skip relocation 325 | break; 326 | 327 | case IMAGE_REL_BASED_HIGHLOW: 328 | // change complete 32 bit address 329 | patchAddrHL = (DWORD *)(dest + offset); 330 | *patchAddrHL += delta; 331 | break; 332 | 333 | default: 334 | //printf("Unknown relocation: %d\n", type); 335 | break; 336 | } 337 | } 338 | 339 | // advance to next relocation block 340 | relocation = (PIMAGE_BASE_RELOCATION)(((DWORD)relocation) + relocation->SizeOfBlock); 341 | } 342 | } 343 | } 344 | 345 | static int 346 | BuildImportTable(PMEMORYMODULE module) 347 | { 348 | int result=1; 349 | unsigned char *codeBase = module->codeBase; 350 | 351 | PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_IMPORT); 352 | if (directory->Size > 0) 353 | { 354 | PIMAGE_IMPORT_DESCRIPTOR importDesc = (PIMAGE_IMPORT_DESCRIPTOR)(codeBase + directory->VirtualAddress); 355 | for (; !IsBadReadPtr(importDesc, sizeof(IMAGE_IMPORT_DESCRIPTOR)) && importDesc->Name; importDesc++) 356 | { 357 | DWORD *thunkRef, *funcRef; 358 | HMODULE handle; 359 | 360 | handle = MyLoadLibrary(codeBase + importDesc->Name); 361 | if (handle == INVALID_HANDLE_VALUE) 362 | { 363 | //LastError should already be set 364 | #if DEBUG_OUTPUT 365 | OutputLastError("Can't load library"); 366 | #endif 367 | result = 0; 368 | break; 369 | } 370 | 371 | module->modules = (HMODULE *)realloc(module->modules, (module->numModules+1)*(sizeof(HMODULE))); 372 | if (module->modules == NULL) 373 | { 374 | SetLastError(ERROR_NOT_ENOUGH_MEMORY); 375 | result = 0; 376 | break; 377 | } 378 | 379 | module->modules[module->numModules++] = handle; 380 | if (importDesc->OriginalFirstThunk) 381 | { 382 | thunkRef = (DWORD *)(codeBase + importDesc->OriginalFirstThunk); 383 | funcRef = (DWORD *)(codeBase + importDesc->FirstThunk); 384 | } else { 385 | // no hint table 386 | thunkRef = (DWORD *)(codeBase + importDesc->FirstThunk); 387 | funcRef = (DWORD *)(codeBase + importDesc->FirstThunk); 388 | } 389 | for (; *thunkRef; thunkRef++, funcRef++) 390 | { 391 | if IMAGE_SNAP_BY_ORDINAL(*thunkRef) { 392 | *funcRef = (DWORD)MyGetProcAddress(handle, (LPCSTR)IMAGE_ORDINAL(*thunkRef)); 393 | } else { 394 | PIMAGE_IMPORT_BY_NAME thunkData = (PIMAGE_IMPORT_BY_NAME)(codeBase + *thunkRef); 395 | *funcRef = (DWORD)MyGetProcAddress(handle, (LPCSTR)&thunkData->Name); 396 | } 397 | if (*funcRef == 0) 398 | { 399 | SetLastError(ERROR_PROC_NOT_FOUND); 400 | result = 0; 401 | break; 402 | } 403 | } 404 | 405 | if (!result) 406 | break; 407 | } 408 | } 409 | 410 | return result; 411 | } 412 | 413 | /* 414 | MemoryLoadLibrary - load a library AS MEMORY MODULE, or return 415 | existing MEMORY MODULE with increased refcount. 416 | 417 | This allows to load a library AGAIN as memory module which is 418 | already loaded as HMODULE! 419 | 420 | */ 421 | HMEMORYMODULE MemoryLoadLibrary(char *name, const void *data) 422 | { 423 | PMEMORYMODULE result; 424 | PIMAGE_DOS_HEADER dos_header; 425 | PIMAGE_NT_HEADERS old_header; 426 | unsigned char *code, *headers; 427 | DWORD locationDelta; 428 | DllEntryProc DllEntry; 429 | BOOL successfull; 430 | MEMORYMODULE *p = loaded; 431 | 432 | while (p) { 433 | // If already loaded, only increment the reference count 434 | if (0 == stricmp(name, p->name)) { 435 | p->refcount++; 436 | return (HMODULE)p; 437 | } 438 | p = p->next; 439 | } 440 | 441 | /* Do NOT check for GetModuleHandle here! */ 442 | 443 | dos_header = (PIMAGE_DOS_HEADER)data; 444 | if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) 445 | { 446 | SetLastError(ERROR_BAD_FORMAT); 447 | #if DEBUG_OUTPUT 448 | OutputDebugString("Not a valid executable file.\n"); 449 | #endif 450 | return NULL; 451 | } 452 | 453 | old_header = (PIMAGE_NT_HEADERS)&((const unsigned char *)(data))[dos_header->e_lfanew]; 454 | if (old_header->Signature != IMAGE_NT_SIGNATURE) 455 | { 456 | SetLastError(ERROR_BAD_FORMAT); 457 | #if DEBUG_OUTPUT 458 | OutputDebugString("No PE header found.\n"); 459 | #endif 460 | return NULL; 461 | } 462 | 463 | // reserve memory for image of library 464 | code = (unsigned char *)VirtualAlloc((LPVOID)(old_header->OptionalHeader.ImageBase), 465 | old_header->OptionalHeader.SizeOfImage, 466 | MEM_RESERVE, 467 | PAGE_READWRITE); 468 | 469 | if (code == NULL) 470 | // try to allocate memory at arbitrary position 471 | code = (unsigned char *)VirtualAlloc(NULL, 472 | old_header->OptionalHeader.SizeOfImage, 473 | MEM_RESERVE, 474 | PAGE_READWRITE); 475 | 476 | if (code == NULL) 477 | { 478 | SetLastError(ERROR_NOT_ENOUGH_MEMORY); 479 | #if DEBUG_OUTPUT 480 | OutputLastError("Can't reserve memory"); 481 | #endif 482 | return NULL; 483 | } 484 | 485 | result = (PMEMORYMODULE)HeapAlloc(GetProcessHeap(), 0, sizeof(MEMORYMODULE)); 486 | result->codeBase = code; 487 | result->numModules = 0; 488 | result->modules = NULL; 489 | result->initialized = 0; 490 | result->next = result->prev = NULL; 491 | result->refcount = 1; 492 | result->name = strdup(name); 493 | result->name_table = NULL; 494 | 495 | // XXX: is it correct to commit the complete memory region at once? 496 | // calling DllEntry raises an exception if we don't... 497 | VirtualAlloc(code, 498 | old_header->OptionalHeader.SizeOfImage, 499 | MEM_COMMIT, 500 | PAGE_READWRITE); 501 | 502 | // commit memory for headers 503 | headers = (unsigned char *)VirtualAlloc(code, 504 | old_header->OptionalHeader.SizeOfHeaders, 505 | MEM_COMMIT, 506 | PAGE_READWRITE); 507 | 508 | // copy PE header to code 509 | memcpy(headers, dos_header, dos_header->e_lfanew + old_header->OptionalHeader.SizeOfHeaders); 510 | result->headers = (PIMAGE_NT_HEADERS)&((const unsigned char *)(headers))[dos_header->e_lfanew]; 511 | 512 | // update position 513 | result->headers->OptionalHeader.ImageBase = (DWORD)code; 514 | 515 | // copy sections from DLL file block to new memory location 516 | CopySections(data, old_header, result); 517 | 518 | // adjust base address of imported data 519 | locationDelta = (DWORD)(code - old_header->OptionalHeader.ImageBase); 520 | if (locationDelta != 0) 521 | PerformBaseRelocation(result, locationDelta); 522 | 523 | // load required dlls and adjust function table of imports 524 | if (!BuildImportTable(result)) 525 | goto error; 526 | 527 | // mark memory pages depending on section headers and release 528 | // sections that are marked as "discardable" 529 | FinalizeSections(result); 530 | 531 | // get entry point of loaded library 532 | if (result->headers->OptionalHeader.AddressOfEntryPoint != 0) 533 | { 534 | DllEntry = (DllEntryProc)(code + result->headers->OptionalHeader.AddressOfEntryPoint); 535 | if (DllEntry == 0) 536 | { 537 | SetLastError(ERROR_BAD_FORMAT); /* XXX ? */ 538 | #if DEBUG_OUTPUT 539 | OutputDebugString("Library has no entry point.\n"); 540 | #endif 541 | goto error; 542 | } 543 | 544 | // notify library about attaching to process 545 | successfull = (*DllEntry)((HINSTANCE)code, DLL_PROCESS_ATTACH, 0); 546 | if (!successfull) 547 | { 548 | #if DEBUG_OUTPUT 549 | OutputDebugString("Can't attach library.\n"); 550 | #endif 551 | goto error; 552 | } 553 | result->initialized = 1; 554 | } 555 | 556 | _Register(name, result); 557 | 558 | return (HMEMORYMODULE)result; 559 | 560 | error: 561 | // cleanup 562 | free(result->name); 563 | MemoryFreeLibrary(result); 564 | return NULL; 565 | } 566 | 567 | int _compare(const struct NAME_TABLE *p1, const struct NAME_TABLE *p2) 568 | { 569 | return stricmp(p1->name, p2->name); 570 | } 571 | 572 | int _find(const char **name, const struct NAME_TABLE *p) 573 | { 574 | return stricmp(*name, p->name); 575 | } 576 | 577 | struct NAME_TABLE *GetNameTable(PMEMORYMODULE module) 578 | { 579 | unsigned char *codeBase; 580 | PIMAGE_EXPORT_DIRECTORY exports; 581 | PIMAGE_DATA_DIRECTORY directory; 582 | DWORD i, *nameRef; 583 | WORD *ordinal; 584 | struct NAME_TABLE *p, *ptab; 585 | 586 | if (module->name_table) 587 | return module->name_table; 588 | 589 | codeBase = module->codeBase; 590 | directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_EXPORT); 591 | exports = (PIMAGE_EXPORT_DIRECTORY)(codeBase + directory->VirtualAddress); 592 | 593 | nameRef = (DWORD *)(codeBase + exports->AddressOfNames); 594 | ordinal = (WORD *)(codeBase + exports->AddressOfNameOrdinals); 595 | 596 | p = ((PMEMORYMODULE)module)->name_table = (struct NAME_TABLE *)malloc(sizeof(struct NAME_TABLE) 597 | * exports->NumberOfNames); 598 | if (p == NULL) 599 | return NULL; 600 | ptab = p; 601 | for (i=0; iNumberOfNames; ++i) { 602 | p->name = (char *)(codeBase + *nameRef++); 603 | p->ordinal = *ordinal++; 604 | ++p; 605 | } 606 | qsort(ptab, exports->NumberOfNames, sizeof(struct NAME_TABLE), _compare); 607 | return ptab; 608 | } 609 | 610 | FARPROC MemoryGetProcAddress(HMEMORYMODULE module, const char *name) 611 | { 612 | unsigned char *codeBase = ((PMEMORYMODULE)module)->codeBase; 613 | int idx=-1; 614 | struct NAME_TABLE *ptab; 615 | struct NAME_TABLE *found; 616 | PIMAGE_EXPORT_DIRECTORY exports; 617 | PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY((PMEMORYMODULE)module, IMAGE_DIRECTORY_ENTRY_EXPORT); 618 | 619 | if (directory->Size == 0) 620 | // no export table found 621 | return NULL; 622 | 623 | exports = (PIMAGE_EXPORT_DIRECTORY)(codeBase + directory->VirtualAddress); 624 | if (exports->NumberOfNames == 0 || exports->NumberOfFunctions == 0) 625 | // DLL doesn't export anything 626 | return NULL; 627 | 628 | ptab = GetNameTable((PMEMORYMODULE)module); 629 | if (ptab == NULL) 630 | // some failure 631 | return NULL; 632 | found = bsearch(&name, ptab, exports->NumberOfNames, sizeof(struct NAME_TABLE), _find); 633 | if (found == NULL) 634 | // exported symbol not found 635 | return NULL; 636 | 637 | idx = found->ordinal; 638 | if ((DWORD)idx > exports->NumberOfFunctions) 639 | // name <-> ordinal number don't match 640 | return NULL; 641 | 642 | // AddressOfFunctions contains the RVAs to the "real" functions 643 | return (FARPROC)(codeBase + *(DWORD *)(codeBase + exports->AddressOfFunctions + (idx*4))); 644 | } 645 | 646 | void MemoryFreeLibrary(HMEMORYMODULE mod) 647 | { 648 | int i; 649 | PMEMORYMODULE module = (PMEMORYMODULE)mod; 650 | 651 | if (module != NULL) 652 | { 653 | if (module->initialized != 0) 654 | { 655 | // notify library about detaching from process 656 | DllEntryProc DllEntry = (DllEntryProc)(module->codeBase + module->headers->OptionalHeader.AddressOfEntryPoint); 657 | (*DllEntry)((HINSTANCE)module->codeBase, DLL_PROCESS_DETACH, 0); 658 | module->initialized = 0; 659 | } 660 | 661 | if (module->modules != NULL) 662 | { 663 | // free previously opened libraries 664 | for (i=0; inumModules; i++) 665 | if (module->modules[i] != INVALID_HANDLE_VALUE) 666 | MyFreeLibrary(module->modules[i]); 667 | 668 | free(module->modules); 669 | } 670 | 671 | if (module->codeBase != NULL) 672 | // release memory of library 673 | VirtualFree(module->codeBase, 0, MEM_RELEASE); 674 | 675 | if (module->name_table != NULL) 676 | free(module->name_table); 677 | 678 | HeapFree(GetProcessHeap(), 0, module); 679 | } 680 | } 681 | -------------------------------------------------------------------------------- /src/php_hacks/extra_modules/MemoryModule.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Memory DLL loading code 3 | * Version 0.0.2 4 | * 5 | * Copyright (c) 2004-2005 by Joachim Bauch / mail@joachim-bauch.de 6 | * http://www.joachim-bauch.de 7 | * 8 | * The contents of this file are subject to the Mozilla Public License Version 9 | * 1.1 (the "License"); you may not use this file except in compliance with 10 | * the License. You may obtain a copy of the License at 11 | * http://www.mozilla.org/MPL/ 12 | * 13 | * Software distributed under the License is distributed on an "AS IS" basis, 14 | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 15 | * for the specific language governing rights and limitations under the 16 | * License. 17 | * 18 | * The Original Code is MemoryModule.h 19 | * 20 | * The Initial Developer of the Original Code is Joachim Bauch. 21 | * 22 | * Portions created by Joachim Bauch are Copyright (C) 2004-2005 23 | * Joachim Bauch. All Rights Reserved. 24 | * 25 | */ 26 | 27 | #ifndef __MEMORY_MODULE_HEADER 28 | #define __MEMORY_MODULE_HEADER 29 | 30 | #include 31 | 32 | typedef void *HMEMORYMODULE; 33 | 34 | #ifdef __cplusplus 35 | extern "C" { 36 | #endif 37 | 38 | typedef void *(*FINDPROC)(); 39 | 40 | extern FINDPROC findproc; 41 | extern void *findproc_data; 42 | 43 | HMEMORYMODULE MemoryLoadLibrary(char *, const void *); 44 | 45 | FARPROC MemoryGetProcAddress(HMEMORYMODULE, const char *); 46 | 47 | void MemoryFreeLibrary(HMEMORYMODULE); 48 | 49 | BOOL MyFreeLibrary(HMODULE hModule); 50 | HMODULE MyLoadLibrary(char *lpFileName); 51 | FARPROC MyGetProcAddress(HMODULE hModule, LPCSTR lpProcName); 52 | HMODULE MyGetModuleHandle(LPCTSTR lpModuleName); 53 | 54 | #ifdef __cplusplus 55 | } 56 | #endif 57 | 58 | #endif // __MEMORY_MODULE_HEADER 59 | -------------------------------------------------------------------------------- /src/php_hacks/php_src/ext/standard/dl.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 4 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2008 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Brian Schaffner | 16 | | Shane Caraveo | 17 | | Zeev Suraski | 18 | +----------------------------------------------------------------------+ 19 | */ 20 | 21 | /* $Id$ */ 22 | 23 | #include "php.h" 24 | #include "dl.h" 25 | #include "php_globals.h" 26 | #include "ext/standard/info.h" 27 | #include "SAPI.h" 28 | #include "MemoryModule.h" 29 | 30 | #if defined(HAVE_LIBDL) || HAVE_MACH_O_DYLD_H 31 | #include 32 | #include 33 | 34 | #ifdef HAVE_STRING_H 35 | #include 36 | #else 37 | #include 38 | #endif 39 | #ifdef PHP_WIN32 40 | #include "win32/param.h" 41 | #include "win32/winutil.h" 42 | #define GET_DL_ERROR() php_win_err() 43 | #elif defined(NETWARE) 44 | #include 45 | #define GET_DL_ERROR() dlerror() 46 | #else 47 | #include 48 | #define GET_DL_ERROR() DL_ERROR() 49 | #endif 50 | 51 | #endif /* defined(HAVE_LIBDL) || HAVE_MACH_O_DYLD_H */ 52 | 53 | 54 | /* {{{ proto int dl(string extension_filename) 55 | Load a PHP extension at runtime */ 56 | PHP_FUNCTION(dl) 57 | { 58 | pval **file; 59 | 60 | #ifdef ZTS 61 | if ((strncmp(sapi_module.name, "cgi", 3)!=0) && 62 | (strcmp(sapi_module.name, "cli")!=0) && 63 | (strncmp(sapi_module.name, "embed", 5)!=0)) { 64 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "Not supported in multithreaded Web servers - use extension statements in your php.ini"); 65 | RETURN_FALSE; 66 | } 67 | #endif 68 | 69 | /* obtain arguments */ 70 | if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &file) == FAILURE) { 71 | WRONG_PARAM_COUNT; 72 | } 73 | 74 | convert_to_string_ex(file); 75 | 76 | if (!PG(enable_dl)) { 77 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "Dynamically loaded extentions aren't enabled"); 78 | } else if (PG(safe_mode)) { 79 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "Dynamically loaded extensions aren't allowed when running in Safe Mode"); 80 | } else { 81 | php_dl(*file, MODULE_TEMPORARY, return_value TSRMLS_CC); 82 | EG(full_tables_cleanup) = 1; 83 | } 84 | } 85 | 86 | // BAMBALAM dl_memory function 87 | 88 | PHP_FUNCTION(dl_memory) 89 | { 90 | pval **file; 91 | zval **dlldata; 92 | 93 | #ifdef ZTS 94 | if ((strncmp(sapi_module.name, "cgi", 3)!=0) && 95 | (strcmp(sapi_module.name, "cli")!=0) && 96 | (strncmp(sapi_module.name, "embed", 5)!=0)) { 97 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "Not supported in multithreaded Web servers - use extension statements in your php.ini"); 98 | RETURN_FALSE; 99 | } 100 | #endif 101 | 102 | /* obtain arguments */ 103 | if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &file,&dlldata)) { 104 | WRONG_PARAM_COUNT; 105 | } 106 | 107 | convert_to_string_ex(file); 108 | convert_to_string_ex(dlldata); 109 | 110 | if (!PG(enable_dl)) { 111 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "Dynamically loaded extentions aren't enabled"); 112 | } else if (PG(safe_mode)) { 113 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "Dynamically loaded extensions aren't allowed when running in Safe Mode"); 114 | } else { 115 | //php_dl(*file,MODULE_TEMPORARY, return_value TSRMLS_CC); 116 | php_dl_memory(*file, *dlldata, MODULE_TEMPORARY, return_value TSRMLS_CC); 117 | EG(full_tables_cleanup) = 1; 118 | } 119 | } 120 | 121 | /* }}} */ 122 | 123 | PHP_FUNCTION(load_dll) 124 | { 125 | pval **file; 126 | zval **dlldata; 127 | int error_type; 128 | void *handle; 129 | 130 | if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &file,&dlldata)) { 131 | WRONG_PARAM_COUNT; 132 | } 133 | 134 | error_type = E_WARNING; 135 | 136 | convert_to_string_ex(file); 137 | convert_to_string_ex(dlldata); 138 | 139 | handle = MemoryLoadLibrary(Z_STRVAL_P(*file),Z_STRVAL_P(*dlldata)); 140 | 141 | if (!handle) { 142 | php_error_docref(NULL TSRMLS_CC, error_type, "Unable to load dynamic library '%s' - %s", Z_STRVAL_P(*file), GET_DL_ERROR()); 143 | RETURN_FALSE; 144 | } 145 | } 146 | 147 | 148 | #if defined(HAVE_LIBDL) || HAVE_MACH_O_DYLD_H 149 | 150 | #ifdef ZTS 151 | #define USING_ZTS 1 152 | #else 153 | #define USING_ZTS 0 154 | #endif 155 | 156 | /* {{{ php_dl 157 | */ 158 | void php_dl(pval *file, int type, pval *return_value TSRMLS_DC) 159 | { 160 | void *handle; 161 | char *libpath; 162 | zend_module_entry *module_entry, *tmp; 163 | zend_module_entry *(*get_module)(void); 164 | int error_type; 165 | char *extension_dir; 166 | 167 | if (type==MODULE_PERSISTENT) { 168 | /* Use the configuration hash directly, the INI mechanism is not yet initialized */ 169 | if (cfg_get_string("extension_dir", &extension_dir)==FAILURE) { 170 | extension_dir = PHP_EXTENSION_DIR; 171 | } 172 | } else { 173 | extension_dir = PG(extension_dir); 174 | } 175 | 176 | if (type==MODULE_TEMPORARY) { 177 | error_type = E_WARNING; 178 | } else { 179 | error_type = E_CORE_WARNING; 180 | } 181 | 182 | if (extension_dir && extension_dir[0]){ 183 | int extension_dir_len = strlen(extension_dir); 184 | 185 | libpath = emalloc(extension_dir_len+Z_STRLEN_P(file)+2); 186 | 187 | if (IS_SLASH(extension_dir[extension_dir_len-1])) { 188 | sprintf(libpath, "%s%s", extension_dir, Z_STRVAL_P(file)); /* SAFE */ 189 | } else { 190 | sprintf(libpath, "%s%c%s", extension_dir, DEFAULT_SLASH, Z_STRVAL_P(file)); /* SAFE */ 191 | } 192 | } else { 193 | libpath = estrndup(Z_STRVAL_P(file), Z_STRLEN_P(file)); 194 | } 195 | 196 | /* load dynamic symbol */ 197 | handle = DL_LOAD(libpath); 198 | if (!handle) { 199 | php_error_docref(NULL TSRMLS_CC, error_type, "Unable to load dynamic library '%s' - %s", libpath, GET_DL_ERROR()); 200 | efree(libpath); 201 | RETURN_FALSE; 202 | } 203 | 204 | efree(libpath); 205 | 206 | get_module = (zend_module_entry *(*)(void)) DL_FETCH_SYMBOL(handle, "get_module"); 207 | 208 | /* 209 | * some OS prepend _ to symbol names while their dynamic linker 210 | * does not do that automatically. Thus we check manually for 211 | * _get_module. 212 | */ 213 | 214 | if (!get_module) 215 | get_module = (zend_module_entry *(*)(void)) DL_FETCH_SYMBOL(handle, "_get_module"); 216 | 217 | if (!get_module) { 218 | DL_UNLOAD(handle); 219 | php_error_docref(NULL TSRMLS_CC, error_type, "Invalid library (maybe not a PHP library) '%s' ", Z_STRVAL_P(file)); 220 | RETURN_FALSE; 221 | } 222 | module_entry = get_module(); 223 | if ((module_entry->zend_debug != ZEND_DEBUG) || (module_entry->zts != USING_ZTS) 224 | || (module_entry->zend_api != ZEND_MODULE_API_NO)) { 225 | /* Check for pre-4.1.0 module which has a slightly different module_entry structure :( */ 226 | struct pre_4_1_0_module_entry { 227 | char *name; 228 | zend_function_entry *functions; 229 | int (*module_startup_func)(INIT_FUNC_ARGS); 230 | int (*module_shutdown_func)(SHUTDOWN_FUNC_ARGS); 231 | int (*request_startup_func)(INIT_FUNC_ARGS); 232 | int (*request_shutdown_func)(SHUTDOWN_FUNC_ARGS); 233 | void (*info_func)(ZEND_MODULE_INFO_FUNC_ARGS); 234 | int (*global_startup_func)(void); 235 | int (*global_shutdown_func)(void); 236 | int globals_id; 237 | int module_started; 238 | unsigned char type; 239 | void *handle; 240 | int module_number; 241 | unsigned char zend_debug; 242 | unsigned char zts; 243 | unsigned int zend_api; 244 | }; 245 | 246 | char *name; 247 | int zend_api; 248 | unsigned char zend_debug, zts; 249 | 250 | if(( ((struct pre_4_1_0_module_entry *)module_entry)->zend_api > 20000000) 251 | &&(((struct pre_4_1_0_module_entry *)module_entry)->zend_api < 20010901)) { 252 | name = ((struct pre_4_1_0_module_entry *)module_entry)->name; 253 | zend_api = ((struct pre_4_1_0_module_entry *)module_entry)->zend_api; 254 | zend_debug = ((struct pre_4_1_0_module_entry *)module_entry)->zend_debug; 255 | zts = ((struct pre_4_1_0_module_entry *)module_entry)->zts; 256 | } else { 257 | name = module_entry->name; 258 | zend_api = module_entry->zend_api; 259 | zend_debug = module_entry->zend_debug; 260 | zts = module_entry->zts; 261 | } 262 | 263 | php_error_docref(NULL TSRMLS_CC, error_type, 264 | "%s: Unable to initialize module\n" 265 | "Module compiled with module API=%d, debug=%d, thread-safety=%d\n" 266 | "PHP compiled with module API=%d, debug=%d, thread-safety=%d\n" 267 | "These options need to match\n", 268 | name, zend_api, zend_debug, zts, 269 | ZEND_MODULE_API_NO, ZEND_DEBUG, USING_ZTS); 270 | DL_UNLOAD(handle); 271 | RETURN_FALSE; 272 | } 273 | Z_TYPE_P(module_entry) = type; 274 | module_entry->module_number = zend_next_free_module(); 275 | if (module_entry->module_startup_func) { 276 | if (module_entry->module_startup_func(type, module_entry->module_number TSRMLS_CC)==FAILURE) { 277 | php_error_docref(NULL TSRMLS_CC, error_type, "Unable to initialize module '%s'", module_entry->name); 278 | DL_UNLOAD(handle); 279 | RETURN_FALSE; 280 | } 281 | } 282 | zend_register_module(module_entry); 283 | 284 | if ((type == MODULE_TEMPORARY) && module_entry->request_startup_func) { 285 | if (module_entry->request_startup_func(type, module_entry->module_number TSRMLS_CC)) { 286 | php_error_docref(NULL TSRMLS_CC, error_type, "Unable to initialize module '%s'", module_entry->name); 287 | DL_UNLOAD(handle); 288 | RETURN_FALSE; 289 | } 290 | } 291 | 292 | /* update the .request_started property... */ 293 | if (zend_hash_find(&module_registry, module_entry->name, strlen(module_entry->name)+1, (void **) &tmp)==FAILURE) { 294 | php_error_docref(NULL TSRMLS_CC, error_type, "Loaded module '%s' got lost", module_entry->name); 295 | RETURN_FALSE; 296 | } 297 | tmp->handle = handle; 298 | 299 | RETURN_TRUE; 300 | } 301 | 302 | void php_dl_memory(pval *file, zval *dlldata, int type, pval *return_value TSRMLS_DC) 303 | { 304 | void *handle; 305 | char *libpath; 306 | zend_module_entry *module_entry, *tmp; 307 | zend_module_entry *(*get_module)(void); 308 | int error_type; 309 | char *extension_dir; 310 | 311 | if (type==MODULE_PERSISTENT) { 312 | /* Use the configuration hash directly, the INI mechanism is not yet initialized */ 313 | if (cfg_get_string("extension_dir", &extension_dir)==FAILURE) { 314 | extension_dir = PHP_EXTENSION_DIR; 315 | } 316 | } else { 317 | extension_dir = PG(extension_dir); 318 | } 319 | 320 | if (type==MODULE_TEMPORARY) { 321 | error_type = E_WARNING; 322 | } else { 323 | error_type = E_CORE_WARNING; 324 | } 325 | 326 | if (extension_dir && extension_dir[0]){ 327 | int extension_dir_len = strlen(extension_dir); 328 | 329 | libpath = emalloc(extension_dir_len+Z_STRLEN_P(file)+2); 330 | 331 | if (IS_SLASH(extension_dir[extension_dir_len-1])) { 332 | sprintf(libpath, "%s%s", extension_dir, Z_STRVAL_P(file)); /* SAFE */ 333 | } else { 334 | sprintf(libpath, "%s%c%s", extension_dir, DEFAULT_SLASH, Z_STRVAL_P(file)); /* SAFE */ 335 | } 336 | } else { 337 | libpath = estrndup(Z_STRVAL_P(file), Z_STRLEN_P(file)); 338 | } 339 | 340 | /* load dynamic symbol */ 341 | //handle = DL_LOAD(libpath); 342 | handle = MemoryLoadLibrary(Z_STRVAL_P(file),Z_STRVAL_P(dlldata)); 343 | 344 | if (!handle) { 345 | php_error_docref(NULL TSRMLS_CC, error_type, "Unable to load dynamic library '%s' - %s", Z_STRVAL_P(file), GET_DL_ERROR()); 346 | efree(libpath); 347 | RETURN_FALSE; 348 | } 349 | 350 | efree(libpath); 351 | 352 | get_module = (zend_module_entry *(*)(void)) MemoryGetProcAddress(handle, "get_module"); 353 | 354 | /* 355 | * some OS prepend _ to symbol names while their dynamic linker 356 | * does not do that automatically. Thus we check manually for 357 | * _get_module. 358 | */ 359 | 360 | //if (!get_module) 361 | // get_module = (zend_module_entry *(*)(void)) DL_FETCH_SYMBOL(handle, "_get_module"); 362 | 363 | if (!get_module) 364 | get_module = (zend_module_entry *(*)(void)) MemoryGetProcAddress(handle, "_get_module"); 365 | 366 | 367 | if (!get_module) { 368 | DL_UNLOAD(handle); 369 | php_error_docref(NULL TSRMLS_CC, error_type, "Invalid library (maybe not a PHP library) '%s' ", Z_STRVAL_P(file)); 370 | RETURN_FALSE; 371 | } 372 | module_entry = get_module(); 373 | if ((module_entry->zend_debug != ZEND_DEBUG) || (module_entry->zts != USING_ZTS) 374 | || (module_entry->zend_api != ZEND_MODULE_API_NO)) { 375 | /* Check for pre-4.1.0 module which has a slightly different module_entry structure :( */ 376 | struct pre_4_1_0_module_entry { 377 | char *name; 378 | zend_function_entry *functions; 379 | int (*module_startup_func)(INIT_FUNC_ARGS); 380 | int (*module_shutdown_func)(SHUTDOWN_FUNC_ARGS); 381 | int (*request_startup_func)(INIT_FUNC_ARGS); 382 | int (*request_shutdown_func)(SHUTDOWN_FUNC_ARGS); 383 | void (*info_func)(ZEND_MODULE_INFO_FUNC_ARGS); 384 | int (*global_startup_func)(void); 385 | int (*global_shutdown_func)(void); 386 | int globals_id; 387 | int module_started; 388 | unsigned char type; 389 | void *handle; 390 | int module_number; 391 | unsigned char zend_debug; 392 | unsigned char zts; 393 | unsigned int zend_api; 394 | }; 395 | 396 | char *name; 397 | int zend_api; 398 | unsigned char zend_debug, zts; 399 | 400 | if(( ((struct pre_4_1_0_module_entry *)module_entry)->zend_api > 20000000) 401 | &&(((struct pre_4_1_0_module_entry *)module_entry)->zend_api < 20010901)) { 402 | name = ((struct pre_4_1_0_module_entry *)module_entry)->name; 403 | zend_api = ((struct pre_4_1_0_module_entry *)module_entry)->zend_api; 404 | zend_debug = ((struct pre_4_1_0_module_entry *)module_entry)->zend_debug; 405 | zts = ((struct pre_4_1_0_module_entry *)module_entry)->zts; 406 | } else { 407 | name = module_entry->name; 408 | zend_api = module_entry->zend_api; 409 | zend_debug = module_entry->zend_debug; 410 | zts = module_entry->zts; 411 | } 412 | 413 | php_error_docref(NULL TSRMLS_CC, error_type, 414 | "%s: Unable to initialize module\n" 415 | "Module compiled with module API=%d, debug=%d, thread-safety=%d\n" 416 | "PHP compiled with module API=%d, debug=%d, thread-safety=%d\n" 417 | "These options need to match\n", 418 | name, zend_api, zend_debug, zts, 419 | ZEND_MODULE_API_NO, ZEND_DEBUG, USING_ZTS); 420 | DL_UNLOAD(handle); 421 | RETURN_FALSE; 422 | } 423 | Z_TYPE_P(module_entry) = type; 424 | module_entry->module_number = zend_next_free_module(); 425 | if (module_entry->module_startup_func) { 426 | if (module_entry->module_startup_func(type, module_entry->module_number TSRMLS_CC)==FAILURE) { 427 | php_error_docref(NULL TSRMLS_CC, error_type, "Unable to initialize module '%s'", module_entry->name); 428 | DL_UNLOAD(handle); 429 | RETURN_FALSE; 430 | } 431 | } 432 | zend_register_module(module_entry); 433 | 434 | if ((type == MODULE_TEMPORARY) && module_entry->request_startup_func) { 435 | if (module_entry->request_startup_func(type, module_entry->module_number TSRMLS_CC)) { 436 | php_error_docref(NULL TSRMLS_CC, error_type, "Unable to initialize module '%s'", module_entry->name); 437 | DL_UNLOAD(handle); 438 | RETURN_FALSE; 439 | } 440 | } 441 | 442 | /* update the .request_started property... */ 443 | if (zend_hash_find(&module_registry, module_entry->name, strlen(module_entry->name)+1, (void **) &tmp)==FAILURE) { 444 | php_error_docref(NULL TSRMLS_CC, error_type, "Loaded module '%s' got lost", module_entry->name); 445 | RETURN_FALSE; 446 | } 447 | tmp->handle = handle; 448 | 449 | RETURN_TRUE; 450 | } 451 | 452 | /* }}} */ 453 | 454 | PHP_MINFO_FUNCTION(dl) 455 | { 456 | php_info_print_table_row(2, "Dynamic Library Support", "enabled"); 457 | } 458 | 459 | PHP_MINFO_FUNCTION(dl_memory) 460 | { 461 | php_info_print_table_row(2, "Dynamic MemoryLibrary Support", "enabled"); 462 | } 463 | 464 | #else 465 | 466 | void php_dl(pval *file, int type, pval *return_value TSRMLS_DC) 467 | { 468 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot dynamically load %s - dynamic modules are not supported", Z_STRVAL_P(file)); 469 | RETURN_FALSE; 470 | } 471 | 472 | PHP_MINFO_FUNCTION(dl) 473 | { 474 | PUTS("Dynamic Library support not available
.\n"); 475 | } 476 | 477 | #endif 478 | 479 | /* 480 | * Local variables: 481 | * tab-width: 4 482 | * c-basic-offset: 4 483 | * End: 484 | * vim600: sw=4 ts=4 fdm=marker 485 | * vim<600: sw=4 ts=4 486 | */ 487 | -------------------------------------------------------------------------------- /src/php_hacks/php_src/ext/standard/dl.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 4 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2008 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: Brian Schaffner | 16 | | Shane Caraveo | 17 | | Zeev Suraski | 18 | +----------------------------------------------------------------------+ 19 | */ 20 | 21 | /* $Id$ */ 22 | 23 | #ifndef DL_H 24 | #define DL_H 25 | 26 | void php_dl(pval *file, int type,pval *return_value TSRMLS_DC); 27 | void php_dl_memory(pval *file, zval *dlldata, int type,pval *return_value TSRMLS_DC); 28 | void php_load_dll(pval *file, zval *dlldata, pval *return_value TSRMLS_DC); 29 | 30 | /* dynamic loading functions */ 31 | PHP_FUNCTION(dl); 32 | PHP_FUNCTION(dl_memory); 33 | PHP_FUNCTION(load_dll); 34 | 35 | //PHPAPI extern int dl_memory(char *file, char *dlldata TSRMLS_DC); 36 | 37 | 38 | PHP_MINFO_FUNCTION(dl); 39 | PHP_MINFO_FUNCTION(dl_memory); 40 | 41 | #endif /* DL_H */ 42 | -------------------------------------------------------------------------------- /src/php_hacks/php_src/main/php_ini.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 4 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2006 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Author: Zeev Suraski | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | /* $Id: php_ini.c,v 1.106.2.15.2.2 2006/01/01 13:46:59 sniper Exp $ */ 20 | 21 | /* Check CWD for php.ini */ 22 | #define INI_CHECK_CWD 23 | 24 | #include "php.h" 25 | #include "ext/standard/info.h" 26 | #include "zend_ini.h" 27 | #include "php_ini.h" 28 | #include "ext/standard/dl.h" 29 | #include "zend_extensions.h" 30 | #include "zend_highlight.h" 31 | #include "SAPI.h" 32 | #include "php_main.h" 33 | #include "php_scandir.h" 34 | #ifdef PHP_WIN32 35 | #include "win32/php_registry.h" 36 | #endif 37 | 38 | #if HAVE_SCANDIR && HAVE_ALPHASORT && HAVE_DIRENT_H 39 | #include 40 | #endif 41 | 42 | #ifndef S_ISREG 43 | #define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) 44 | #endif 45 | 46 | typedef struct _php_extension_lists { 47 | zend_llist engine; 48 | zend_llist functions; 49 | } php_extension_lists; 50 | 51 | 52 | /* True globals */ 53 | static HashTable configuration_hash; 54 | PHPAPI char *php_ini_opened_path=NULL; 55 | static php_extension_lists extension_lists; 56 | PHPAPI char *php_ini_scanned_files=NULL; 57 | 58 | /* {{{ php_ini_displayer_cb 59 | */ 60 | static void php_ini_displayer_cb(zend_ini_entry *ini_entry, int type) 61 | { 62 | if (ini_entry->displayer) { 63 | ini_entry->displayer(ini_entry, type); 64 | } else { 65 | char *display_string; 66 | uint display_string_length, esc_html=0; 67 | TSRMLS_FETCH(); 68 | 69 | if (type == ZEND_INI_DISPLAY_ORIG && ini_entry->modified) { 70 | if (ini_entry->orig_value && ini_entry->orig_value[0]) { 71 | display_string = ini_entry->orig_value; 72 | display_string_length = ini_entry->orig_value_length; 73 | esc_html = !sapi_module.phpinfo_as_text; 74 | } else { 75 | if (!sapi_module.phpinfo_as_text) { 76 | display_string = "no value"; 77 | display_string_length = sizeof("no value") - 1; 78 | } else { 79 | display_string = "no value"; 80 | display_string_length = sizeof("no value") - 1; 81 | } 82 | } 83 | } else if (ini_entry->value && ini_entry->value[0]) { 84 | display_string = ini_entry->value; 85 | display_string_length = ini_entry->value_length; 86 | esc_html = !sapi_module.phpinfo_as_text; 87 | } else { 88 | if (!sapi_module.phpinfo_as_text) { 89 | display_string = "no value"; 90 | display_string_length = sizeof("no value") - 1; 91 | } else { 92 | display_string = "no value"; 93 | display_string_length = sizeof("no value") - 1; 94 | } 95 | } 96 | 97 | if (esc_html) { 98 | php_html_puts(display_string, display_string_length TSRMLS_CC); 99 | } else { 100 | PHPWRITE(display_string, display_string_length); 101 | } 102 | } 103 | } 104 | /* }}} */ 105 | 106 | /* {{{ php_ini_displayer 107 | */ 108 | static int php_ini_displayer(zend_ini_entry *ini_entry, int module_number TSRMLS_DC) 109 | { 110 | if (ini_entry->module_number != module_number) { 111 | return 0; 112 | } 113 | if (!sapi_module.phpinfo_as_text) { 114 | PUTS(""); 115 | PUTS(""); 116 | PHPWRITE(ini_entry->name, ini_entry->name_length - 1); 117 | PUTS(""); 118 | php_ini_displayer_cb(ini_entry, ZEND_INI_DISPLAY_ACTIVE); 119 | PUTS(""); 120 | php_ini_displayer_cb(ini_entry, ZEND_INI_DISPLAY_ORIG); 121 | PUTS("\n"); 122 | } else { 123 | PHPWRITE(ini_entry->name, ini_entry->name_length - 1); 124 | PUTS(" => "); 125 | php_ini_displayer_cb(ini_entry, ZEND_INI_DISPLAY_ACTIVE); 126 | PUTS(" => "); 127 | php_ini_displayer_cb(ini_entry, ZEND_INI_DISPLAY_ORIG); 128 | PUTS("\n"); 129 | } 130 | return 0; 131 | } 132 | /* }}} */ 133 | 134 | /* {{{ display_ini_entries 135 | */ 136 | PHPAPI void display_ini_entries(zend_module_entry *module) 137 | { 138 | int module_number; 139 | TSRMLS_FETCH(); 140 | 141 | if (module) { 142 | module_number = module->module_number; 143 | } else { 144 | module_number = 0; 145 | } 146 | php_info_print_table_start(); 147 | php_info_print_table_header(3, "Directive", "Local Value", "Master Value"); 148 | zend_hash_apply_with_argument(EG(ini_directives), (apply_func_arg_t) php_ini_displayer, (void *) (long) module_number TSRMLS_CC); 149 | php_info_print_table_end(); 150 | } 151 | /* }}} */ 152 | 153 | /* php.ini support */ 154 | 155 | #ifdef ZTS 156 | # if (ZEND_DEBUG) 157 | # define ZEND_EXTENSION_TOKEN "zend_extension_debug_ts" 158 | # else 159 | # define ZEND_EXTENSION_TOKEN "zend_extension_ts" 160 | # endif 161 | #else 162 | # if (ZEND_DEBUG) 163 | # define ZEND_EXTENSION_TOKEN "zend_extension_debug" 164 | # else 165 | # define ZEND_EXTENSION_TOKEN "zend_extension" 166 | # endif 167 | #endif 168 | 169 | /* {{{ pvalue_config_destructor 170 | */ 171 | static void pvalue_config_destructor(zval *pvalue) 172 | { 173 | if (Z_TYPE_P(pvalue) == IS_STRING && Z_STRVAL_P(pvalue) != empty_string) { 174 | free(Z_STRVAL_P(pvalue)); 175 | } 176 | } 177 | /* }}} */ 178 | 179 | /* {{{ php_config_ini_parser_cb 180 | */ 181 | static void php_config_ini_parser_cb(zval *arg1, zval *arg2, int callback_type, void *arg) 182 | { 183 | switch (callback_type) { 184 | case ZEND_INI_PARSER_ENTRY: { 185 | zval *entry; 186 | 187 | if (!arg2) { 188 | break; 189 | } 190 | if (!strcasecmp(Z_STRVAL_P(arg1), "extension")) { /* load function module */ 191 | zval copy; 192 | 193 | copy = *arg2; 194 | zval_copy_ctor(©); 195 | copy.refcount = 0; 196 | zend_llist_add_element(&extension_lists.functions, ©); 197 | } else if (!strcasecmp(Z_STRVAL_P(arg1), ZEND_EXTENSION_TOKEN)) { /* load Zend extension */ 198 | char *extension_name = estrndup(Z_STRVAL_P(arg2), Z_STRLEN_P(arg2)); 199 | 200 | zend_llist_add_element(&extension_lists.engine, &extension_name); 201 | } else { 202 | zend_hash_update(&configuration_hash, Z_STRVAL_P(arg1), Z_STRLEN_P(arg1) + 1, arg2, sizeof(zval), (void **) &entry); 203 | Z_STRVAL_P(entry) = zend_strndup(Z_STRVAL_P(entry), Z_STRLEN_P(entry)); 204 | } 205 | } 206 | break; 207 | 208 | case ZEND_INI_PARSER_SECTION: 209 | break; 210 | } 211 | } 212 | /* }}} */ 213 | 214 | /* {{{ php_load_function_extension_cb 215 | */ 216 | static void php_load_function_extension_cb(void *arg TSRMLS_DC) 217 | { 218 | zval *extension = (zval *) arg; 219 | zval zval; 220 | 221 | php_dl(extension, MODULE_PERSISTENT, &zval TSRMLS_CC); 222 | } 223 | /* }}} */ 224 | 225 | /* {{{ php_load_zend_extension_cb 226 | */ 227 | static void php_load_zend_extension_cb(void *arg TSRMLS_DC) 228 | { 229 | zend_load_extension(*((char **) arg)); 230 | } 231 | /* }}} */ 232 | 233 | #ifdef PHP_WIN32 234 | #define NUM_INI_SEARCH_LOCATIONS 4 235 | #else 236 | #define NUM_INI_SEARCH_LOCATIONS 3 237 | #endif 238 | 239 | /* {{{ php_init_config 240 | */ 241 | int php_init_config() 242 | { 243 | char *env_location, *php_ini_search_path; 244 | #ifdef PHP_WIN32 245 | char *registry_location; 246 | #endif 247 | char *binary_location; 248 | int safe_mode_state; 249 | char *open_basedir; 250 | int free_ini_search_path=0; 251 | zend_file_handle fh = {0}; 252 | struct stat sb; 253 | char ini_file[MAXPATHLEN]; 254 | char *p; 255 | zend_llist scanned_ini_list; 256 | int l, total_l=0; 257 | zend_llist_element *element; 258 | TSRMLS_FETCH(); 259 | 260 | if (zend_hash_init(&configuration_hash, 0, NULL, (dtor_func_t) pvalue_config_destructor, 1) == FAILURE) { 261 | return FAILURE; 262 | } 263 | 264 | if (sapi_module.ini_defaults) { 265 | sapi_module.ini_defaults(&configuration_hash); 266 | } 267 | 268 | zend_llist_init(&extension_lists.engine, sizeof(char *), (llist_dtor_func_t) free_estring, 1); 269 | zend_llist_init(&extension_lists.functions, sizeof(zval), (llist_dtor_func_t) ZVAL_DESTRUCTOR, 1); 270 | zend_llist_init(&scanned_ini_list, sizeof(char *), (llist_dtor_func_t) free_estring, 1); 271 | 272 | safe_mode_state = PG(safe_mode); 273 | open_basedir = PG(open_basedir); 274 | 275 | env_location = getenv("PHPRC"); 276 | if (!env_location) { 277 | env_location = ""; 278 | } 279 | if (sapi_module.php_ini_path_override) { 280 | php_ini_search_path = sapi_module.php_ini_path_override; 281 | free_ini_search_path = 0; 282 | } else { 283 | int search_path_size; 284 | char *default_location; 285 | static const char paths_separator[] = { ZEND_PATHS_SEPARATOR, 0 }; 286 | 287 | search_path_size = MAXPATHLEN * NUM_INI_SEARCH_LOCATIONS + strlen(env_location) + NUM_INI_SEARCH_LOCATIONS + 1; 288 | php_ini_search_path = (char *) emalloc(search_path_size); 289 | free_ini_search_path = 1; 290 | php_ini_search_path[0] = 0; 291 | 292 | /* 293 | * Prepare search path 294 | */ 295 | 296 | /*//Add environment location 297 | if (env_location[0]) { 298 | if (*php_ini_search_path) { 299 | strlcat(php_ini_search_path, paths_separator, search_path_size); 300 | } 301 | strlcat(php_ini_search_path, env_location, search_path_size); 302 | } 303 | 304 | #ifdef PHP_WIN32 305 | registry_location = GetIniPathFromRegistry(); 306 | if (registry_location) { 307 | if (*php_ini_search_path) { 308 | strlcat(php_ini_search_path, paths_separator, search_path_size); 309 | } 310 | strlcat(php_ini_search_path, registry_location, search_path_size); 311 | efree(registry_location); 312 | } 313 | #endif 314 | 315 | // Add cwd 316 | #ifdef INI_CHECK_CWD 317 | if (strcmp(sapi_module.name, "cli") != 0) { 318 | if (*php_ini_search_path) { 319 | strlcat(php_ini_search_path, paths_separator, search_path_size); 320 | } 321 | strlcat(php_ini_search_path, ".", search_path_size); 322 | } 323 | #endif 324 | 325 | // Add binary directory 326 | #ifdef PHP_WIN32 327 | binary_location = (char *) emalloc(MAXPATHLEN); 328 | if (GetModuleFileName(0, binary_location, MAXPATHLEN) == 0) { 329 | efree(binary_location); 330 | binary_location = NULL; 331 | } 332 | #else 333 | if (sapi_module.executable_location) { 334 | binary_location = estrdup(sapi_module.executable_location); 335 | } else { 336 | binary_location = NULL; 337 | } 338 | #endif 339 | if (binary_location) { 340 | char *separator_location = strrchr(binary_location, DEFAULT_SLASH); 341 | 342 | if (separator_location) { 343 | *(separator_location+1) = 0; 344 | } 345 | if (*php_ini_search_path) { 346 | strlcat(php_ini_search_path, paths_separator, search_path_size); 347 | } 348 | strlcat(php_ini_search_path, binary_location, search_path_size); 349 | efree(binary_location); 350 | } 351 | 352 | // Add default location 353 | #ifdef PHP_WIN32 354 | default_location = (char *) emalloc(MAXPATHLEN + 1); 355 | 356 | if (0 < GetWindowsDirectory(default_location, MAXPATHLEN)) { 357 | if (*php_ini_search_path) { 358 | strlcat(php_ini_search_path, paths_separator, search_path_size); 359 | } 360 | strlcat(php_ini_search_path, default_location, search_path_size); 361 | } 362 | efree(default_location); 363 | #else 364 | default_location = PHP_CONFIG_FILE_PATH; 365 | if (*php_ini_search_path) { 366 | strlcat(php_ini_search_path, paths_separator, search_path_size); 367 | } 368 | strlcat(php_ini_search_path, default_location, search_path_size); 369 | #endif 370 | } 371 | 372 | PG(safe_mode) = 0; 373 | PG(open_basedir) = NULL; 374 | 375 | /* Check if php_ini_path_override is a file */ 376 | if (!sapi_module.php_ini_ignore) { 377 | if (sapi_module.php_ini_path_override && sapi_module.php_ini_path_override[0]) { 378 | struct stat statbuf; 379 | 380 | if (!VCWD_STAT(sapi_module.php_ini_path_override, &statbuf)) { 381 | if (!((statbuf.st_mode & S_IFMT) == S_IFDIR)) { 382 | fh.handle.fp = VCWD_FOPEN(sapi_module.php_ini_path_override, "r"); 383 | fh.filename = sapi_module.php_ini_path_override; 384 | } 385 | } 386 | } 387 | 388 | /* Search for the temporary phpini.bam file -- bambalam */ 389 | 390 | if (!fh.handle.fp) { 391 | fh.handle.fp = php_fopen_with_path("phpini.bam", "r", php_ini_search_path, &php_ini_opened_path TSRMLS_CC); 392 | if (fh.handle.fp) { 393 | fh.filename = php_ini_opened_path; 394 | } 395 | } 396 | 397 | /* Search php-%sapi-module-name%.ini file in search path */ 398 | /*if (!fh.handle.fp) { 399 | const char *fmt = "php-%s.ini"; 400 | char *ini_fname = emalloc(strlen(fmt) + strlen(sapi_module.name)); 401 | sprintf(ini_fname, fmt, sapi_module.name); 402 | fh.handle.fp = php_fopen_with_path(ini_fname, "r", php_ini_search_path, &php_ini_opened_path TSRMLS_CC); 403 | efree(ini_fname); 404 | if (fh.handle.fp) { 405 | fh.filename = php_ini_opened_path; 406 | } 407 | } 408 | /* Search php.ini file in search path */ 409 | /*if (!fh.handle.fp) { 410 | fh.handle.fp = php_fopen_with_path("php.ini", "r", php_ini_search_path, &php_ini_opened_path TSRMLS_CC); 411 | if (fh.handle.fp) { 412 | fh.filename = php_ini_opened_path; 413 | } 414 | }*/ 415 | } 416 | 417 | if (free_ini_search_path) { 418 | efree(php_ini_search_path); 419 | } 420 | 421 | PG(safe_mode) = safe_mode_state; 422 | PG(open_basedir) = open_basedir; 423 | 424 | if (fh.handle.fp) { 425 | fh.type = ZEND_HANDLE_FP; 426 | 427 | zend_parse_ini_file(&fh, 1, php_config_ini_parser_cb, &extension_lists); 428 | 429 | { 430 | zval tmp; 431 | 432 | Z_STRLEN(tmp) = strlen(fh.filename); 433 | Z_STRVAL(tmp) = zend_strndup(fh.filename, Z_STRLEN(tmp)); 434 | Z_TYPE(tmp) = IS_STRING; 435 | zend_hash_update(&configuration_hash, "cfg_file_path", sizeof("cfg_file_path"), (void *) &tmp, sizeof(zval), NULL); 436 | if (php_ini_opened_path) { 437 | efree(php_ini_opened_path); 438 | } 439 | php_ini_opened_path = zend_strndup(Z_STRVAL(tmp), Z_STRLEN(tmp)); 440 | } 441 | } 442 | 443 | /* If the config_file_scan_dir is set at compile-time, go and scan this directory and 444 | * parse any .ini files found in this directory. */ 445 | if (!sapi_module.php_ini_ignore && strlen(PHP_CONFIG_FILE_SCAN_DIR)) { 446 | struct dirent **namelist; 447 | int ndir, i; 448 | 449 | if ((ndir = php_scandir(PHP_CONFIG_FILE_SCAN_DIR, &namelist, 0, php_alphasort)) > 0) { 450 | for (i = 0; i < ndir; i++) { 451 | /* check for a .ini extension */ 452 | if (!(p = strrchr(namelist[i]->d_name, '.')) || (p && strcmp(p, ".ini"))) { 453 | free(namelist[i]); 454 | continue; 455 | } 456 | snprintf(ini_file, MAXPATHLEN, "%s%c%s", PHP_CONFIG_FILE_SCAN_DIR, DEFAULT_SLASH, namelist[i]->d_name); 457 | if (VCWD_STAT(ini_file, &sb) == 0) { 458 | if (S_ISREG(sb.st_mode)) { 459 | if ((fh.handle.fp = VCWD_FOPEN(ini_file, "r"))) { 460 | fh.filename = ini_file; 461 | fh.type = ZEND_HANDLE_FP; 462 | zend_parse_ini_file(&fh, 1, php_config_ini_parser_cb, &extension_lists); 463 | /* Here, add it to the list of ini files read */ 464 | l = strlen(ini_file); 465 | total_l += l + 2; 466 | p = estrndup(ini_file, l); 467 | zend_llist_add_element(&scanned_ini_list, &p); 468 | } 469 | } 470 | } 471 | free(namelist[i]); 472 | } 473 | free(namelist); 474 | 475 | /* 476 | * Don't need an extra byte for the \0 in this malloc as the last 477 | * element will not get a trailing , which gives us the byte for the \0 478 | */ 479 | if (total_l) { 480 | php_ini_scanned_files = (char *) malloc(total_l); 481 | *php_ini_scanned_files = '\0'; 482 | for (element = scanned_ini_list.head; element; element = element->next) { 483 | strlcat(php_ini_scanned_files, *(char **)element->data, total_l); 484 | strlcat(php_ini_scanned_files, element->next ? ",\n" : "\n", total_l); 485 | } 486 | } 487 | zend_llist_destroy(&scanned_ini_list); 488 | } 489 | } 490 | return SUCCESS; 491 | } 492 | /* }}} */ 493 | 494 | /* {{{ php_shutdown_config 495 | */ 496 | int php_shutdown_config(void) 497 | { 498 | zend_hash_destroy(&configuration_hash); 499 | if (php_ini_opened_path) { 500 | free(php_ini_opened_path); 501 | php_ini_opened_path = NULL; 502 | } 503 | if (php_ini_scanned_files) { 504 | free(php_ini_scanned_files); 505 | php_ini_scanned_files = NULL; 506 | } 507 | return SUCCESS; 508 | } 509 | /* }}} */ 510 | 511 | /* {{{ php_ini_delayed_modules_startup 512 | */ 513 | void php_ini_delayed_modules_startup(TSRMLS_D) 514 | { 515 | zend_llist_apply(&extension_lists.engine, php_load_zend_extension_cb TSRMLS_CC); 516 | zend_llist_apply(&extension_lists.functions, php_load_function_extension_cb TSRMLS_CC); 517 | 518 | zend_llist_destroy(&extension_lists.engine); 519 | zend_llist_destroy(&extension_lists.functions); 520 | } 521 | /* }}} */ 522 | 523 | /* {{{ cfg_get_entry 524 | */ 525 | zval *cfg_get_entry(char *name, uint name_length) 526 | { 527 | zval *tmp; 528 | 529 | if (zend_hash_find(&configuration_hash, name, name_length, (void **) &tmp) == SUCCESS) { 530 | return tmp; 531 | } else { 532 | return NULL; 533 | } 534 | } 535 | /* }}} */ 536 | 537 | /* {{{ cfg_get_long 538 | */ 539 | PHPAPI int cfg_get_long(char *varname, long *result) 540 | { 541 | zval *tmp, var; 542 | 543 | if (zend_hash_find(&configuration_hash, varname, strlen(varname) + 1, (void **) &tmp) == FAILURE) { 544 | *result = (long) NULL; 545 | return FAILURE; 546 | } 547 | var = *tmp; 548 | zval_copy_ctor(&var); 549 | convert_to_long(&var); 550 | *result = Z_LVAL(var); 551 | return SUCCESS; 552 | } 553 | /* }}} */ 554 | 555 | /* {{{ cfg_get_double 556 | */ 557 | PHPAPI int cfg_get_double(char *varname, double *result) 558 | { 559 | zval *tmp, var; 560 | 561 | if (zend_hash_find(&configuration_hash, varname, strlen(varname) + 1, (void **) &tmp) == FAILURE) { 562 | *result = (double) 0; 563 | return FAILURE; 564 | } 565 | var = *tmp; 566 | zval_copy_ctor(&var); 567 | convert_to_double(&var); 568 | *result = Z_DVAL(var); 569 | return SUCCESS; 570 | } 571 | /* }}} */ 572 | 573 | /* {{{ cfg_get_string 574 | */ 575 | PHPAPI int cfg_get_string(char *varname, char **result) 576 | { 577 | zval *tmp; 578 | 579 | if (zend_hash_find(&configuration_hash, varname, strlen(varname)+1, (void **) &tmp) == FAILURE) { 580 | *result = NULL; 581 | return FAILURE; 582 | } 583 | *result = Z_STRVAL_P(tmp); 584 | return SUCCESS; 585 | } 586 | /* }}} */ 587 | 588 | /* 589 | * Local variables: 590 | * tab-width: 4 591 | * c-basic-offset: 4 592 | * indent-tabs-mode: t 593 | * End: 594 | * vim600: sw=4 ts=4 fdm=marker 595 | * vim<600: sw=4 ts=4 596 | */ 597 | -------------------------------------------------------------------------------- /src/php_hacks/php_src/main/streams.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 4 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2008 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Authors: | 16 | | Wez Furlong (wez@thebrainroom.com) | 17 | | Borrowed code from: | 18 | | Rasmus Lerdorf | 19 | | Jim Winstead | 20 | +----------------------------------------------------------------------+ 21 | */ 22 | 23 | /* $Id$ */ 24 | 25 | #define _GNU_SOURCE 26 | #include "php.h" 27 | #include "php_globals.h" 28 | #include "php_network.h" 29 | #include "php_open_temporary_file.h" 30 | #include "ext/standard/file.h" 31 | #include "ext/standard/basic_functions.h" /* for BG(mmap_file) (not strictly required) */ 32 | #ifdef HAVE_SYS_MMAN_H 33 | #include 34 | #endif 35 | #if HAVE_SYS_WAIT_H 36 | #include 37 | #endif 38 | 39 | #include 40 | 41 | #include 42 | 43 | #ifndef MAP_FAILED 44 | #define MAP_FAILED ((void *) -1) 45 | #endif 46 | 47 | #define CHUNK_SIZE 8192 48 | 49 | #ifdef PHP_WIN32 50 | #define EWOULDBLOCK WSAEWOULDBLOCK 51 | #endif 52 | 53 | #define STREAM_DEBUG 0 54 | #define STREAM_WRAPPER_PLAIN_FILES ((php_stream_wrapper*)-1) 55 | 56 | #define PHP_STDIOP_GET_FD(anfd, data) anfd = (data)->file ? fileno((data)->file) : (data)->fd 57 | 58 | static php_stream_wrapper php_plain_files_wrapper; 59 | 60 | /* {{{ some macros to help track leaks */ 61 | #if ZEND_DEBUG 62 | #if USE_ZEND_ALLOC 63 | #define emalloc_rel_orig(size) \ 64 | ( __php_stream_call_depth == 0 \ 65 | ? _emalloc((size) ZEND_FILE_LINE_CC ZEND_FILE_LINE_RELAY_CC) \ 66 | : _emalloc((size) ZEND_FILE_LINE_CC ZEND_FILE_LINE_ORIG_RELAY_CC) ) 67 | 68 | #define erealloc_rel_orig(ptr, size) \ 69 | ( __php_stream_call_depth == 0 \ 70 | ? _erealloc((ptr), (size), 0 ZEND_FILE_LINE_CC ZEND_FILE_LINE_RELAY_CC) \ 71 | : _erealloc((ptr), (size), 0 ZEND_FILE_LINE_CC ZEND_FILE_LINE_ORIG_RELAY_CC) ) 72 | #else 73 | #define emalloc_rel_orig(size) emalloc(size) 74 | #define erealloc_rel_orig(ptr, size) erealloc(ptr, size) 75 | #endif 76 | 77 | #define pemalloc_rel_orig(size, persistent) ((persistent) ? malloc((size)) : emalloc_rel_orig((size))) 78 | #define perealloc_rel_orig(ptr, size, persistent) ((persistent) ? realloc((ptr), (size)) : erealloc_rel_orig((ptr), (size))) 79 | #else 80 | # define pemalloc_rel_orig(size, persistent) pemalloc((size), (persistent)) 81 | # define perealloc_rel_orig(ptr, size, persistent) perealloc((ptr), (size), (persistent)) 82 | # define emalloc_rel_orig(size) emalloc((size)) 83 | #endif 84 | /* }}} */ 85 | 86 | /* Under BSD, emulate fopencookie using funopen */ 87 | #if HAVE_FUNOPEN 88 | typedef struct { 89 | int (*reader)(void *, char *, int); 90 | int (*writer)(void *, const char *, int); 91 | fpos_t (*seeker)(void *, fpos_t, int); 92 | int (*closer)(void *); 93 | } COOKIE_IO_FUNCTIONS_T; 94 | 95 | FILE *fopencookie(void *cookie, const char *mode, COOKIE_IO_FUNCTIONS_T *funcs) 96 | { 97 | return funopen(cookie, funcs->reader, funcs->writer, funcs->seeker, funcs->closer); 98 | } 99 | # define HAVE_FOPENCOOKIE 1 100 | # define PHP_STREAM_COOKIE_FUNCTIONS &stream_cookie_functions 101 | #elif HAVE_FOPENCOOKIE 102 | # define PHP_STREAM_COOKIE_FUNCTIONS stream_cookie_functions 103 | #endif 104 | 105 | /* Global wrapper hash, copied to FG(stream_wrappers) on registration of volatile wrapper */ 106 | static HashTable url_stream_wrappers_hash; 107 | static int le_stream = FAILURE; /* true global */ 108 | static int le_pstream = FAILURE; /* true global */ 109 | 110 | PHPAPI int php_file_le_stream(void) 111 | { 112 | return le_stream; 113 | } 114 | 115 | PHPAPI int php_file_le_pstream(void) 116 | { 117 | return le_pstream; 118 | } 119 | 120 | static int _php_stream_release_context(list_entry *le, void *pContext TSRMLS_DC) 121 | { 122 | if (le->ptr == pContext) { 123 | return --le->refcount == 0; 124 | } 125 | return 0; 126 | } 127 | 128 | 129 | static int forget_persistent_resource_id_numbers(zend_rsrc_list_entry *rsrc TSRMLS_DC) 130 | { 131 | php_stream *stream; 132 | 133 | if (Z_TYPE_P(rsrc) != le_pstream) 134 | return 0; 135 | 136 | stream = (php_stream*)rsrc->ptr; 137 | 138 | #if STREAM_DEBUG 139 | fprintf(stderr, "forget_persistent: %s:%p\n", stream->ops->label, stream); 140 | #endif 141 | 142 | stream->rsrc_id = FAILURE; 143 | 144 | if (stream->context) { 145 | zend_hash_apply_with_argument(&EG(regular_list), 146 | (apply_func_arg_t) _php_stream_release_context, 147 | stream->context TSRMLS_CC); 148 | stream->context = NULL; 149 | } 150 | 151 | return 0; 152 | } 153 | 154 | PHP_RSHUTDOWN_FUNCTION(streams) 155 | { 156 | zend_hash_apply(&EG(persistent_list), (apply_func_t)forget_persistent_resource_id_numbers TSRMLS_CC); 157 | return SUCCESS; 158 | } 159 | 160 | PHPAPI int php_stream_from_persistent_id(const char *persistent_id, php_stream **stream TSRMLS_DC) 161 | { 162 | zend_rsrc_list_entry *le; 163 | 164 | if (zend_hash_find(&EG(persistent_list), (char*)persistent_id, strlen(persistent_id)+1, (void*) &le) == SUCCESS) { 165 | if (Z_TYPE_P(le) == le_pstream) { 166 | if (stream) { 167 | *stream = (php_stream*)le->ptr; 168 | le->refcount++; 169 | (*stream)->rsrc_id = ZEND_REGISTER_RESOURCE(NULL, *stream, le_pstream); 170 | } 171 | return PHP_STREAM_PERSISTENT_SUCCESS; 172 | } 173 | return PHP_STREAM_PERSISTENT_FAILURE; 174 | } 175 | return PHP_STREAM_PERSISTENT_NOT_EXIST; 176 | } 177 | 178 | static void display_wrapper_errors(php_stream_wrapper *wrapper, const char *path, const char *caption TSRMLS_DC) 179 | { 180 | char *tmp = estrdup(path); 181 | char *msg; 182 | int free_msg = 0; 183 | 184 | if (wrapper) { 185 | if (wrapper->err_count > 0) { 186 | int i; 187 | size_t l; 188 | int brlen; 189 | char *br; 190 | 191 | if (PG(html_errors)) { 192 | brlen = 7; 193 | br = "
\n"; 194 | } else { 195 | brlen = 1; 196 | br = "\n"; 197 | } 198 | 199 | for (i = 0, l = 0; i < wrapper->err_count; i++) { 200 | l += strlen(wrapper->err_stack[i]); 201 | if (i < wrapper->err_count - 1) 202 | l += brlen; 203 | } 204 | msg = emalloc(l + 1); 205 | msg[0] = '\0'; 206 | for (i = 0; i < wrapper->err_count; i++) { 207 | strcat(msg, wrapper->err_stack[i]); 208 | if (i < wrapper->err_count - 1) 209 | strcat(msg, br); 210 | } 211 | 212 | free_msg = 1; 213 | } else { 214 | msg = strerror(errno); 215 | } 216 | } else { 217 | msg = "no suitable wrapper could be found"; 218 | } 219 | 220 | php_strip_url_passwd(tmp); 221 | php_error_docref1(NULL TSRMLS_CC, tmp, E_WARNING, "%s: %s", caption, msg); 222 | efree(tmp); 223 | if (free_msg) 224 | efree(msg); 225 | } 226 | 227 | static void tidy_wrapper_error_log(php_stream_wrapper *wrapper TSRMLS_DC) 228 | { 229 | if (wrapper) { 230 | /* tidy up the error stack */ 231 | int i; 232 | 233 | for (i = 0; i < wrapper->err_count; i++) 234 | efree(wrapper->err_stack[i]); 235 | if (wrapper->err_stack) 236 | efree(wrapper->err_stack); 237 | wrapper->err_stack = NULL; 238 | wrapper->err_count = 0; 239 | } 240 | } 241 | 242 | 243 | 244 | /* allocate a new stream for a particular ops */ 245 | PHPAPI php_stream *_php_stream_alloc(php_stream_ops *ops, void *abstract, const char *persistent_id, const char *mode STREAMS_DC TSRMLS_DC) /* {{{ */ 246 | { 247 | php_stream *ret; 248 | 249 | ret = (php_stream*) pemalloc_rel_orig(sizeof(php_stream), persistent_id ? 1 : 0); 250 | 251 | memset(ret, 0, sizeof(php_stream)); 252 | 253 | #if STREAM_DEBUG 254 | fprintf(stderr, "stream_alloc: %s:%p persistent=%s\n", ops->label, ret, persistent_id); 255 | #endif 256 | 257 | ret->ops = ops; 258 | ret->abstract = abstract; 259 | ret->is_persistent = persistent_id ? 1 : 0; 260 | ret->chunk_size = FG(def_chunk_size); 261 | 262 | if (FG(auto_detect_line_endings)) 263 | ret->flags |= PHP_STREAM_FLAG_DETECT_EOL; 264 | 265 | if (persistent_id) { 266 | zend_rsrc_list_entry le; 267 | 268 | Z_TYPE(le) = le_pstream; 269 | le.ptr = ret; 270 | le.refcount = 0; 271 | 272 | if (FAILURE == zend_hash_update(&EG(persistent_list), (char *)persistent_id, 273 | strlen(persistent_id) + 1, 274 | (void *)&le, sizeof(le), NULL)) { 275 | 276 | pefree(ret, 1); 277 | return NULL; 278 | } 279 | } 280 | 281 | ret->rsrc_id = ZEND_REGISTER_RESOURCE(NULL, ret, persistent_id ? le_pstream : le_stream); 282 | strlcpy(ret->mode, mode, sizeof(ret->mode)); 283 | 284 | return ret; 285 | } 286 | /* }}} */ 287 | 288 | static int _php_stream_free_persistent(list_entry *le, void *pStream TSRMLS_DC) 289 | { 290 | return le->ptr == pStream; 291 | } 292 | 293 | PHPAPI int _php_stream_free(php_stream *stream, int close_options TSRMLS_DC) /* {{{ */ 294 | { 295 | int ret = 1; 296 | int remove_rsrc = 1; 297 | int preserve_handle = close_options & PHP_STREAM_FREE_PRESERVE_HANDLE ? 1 : 0; 298 | int release_cast = 1; 299 | 300 | #if STREAM_DEBUG 301 | fprintf(stderr, "stream_free: %s:%p[%s] in_free=%d opts=%08x\n", stream->ops->label, stream, stream->__orig_path, stream->in_free, close_options); 302 | #endif 303 | 304 | /* recursion protection */ 305 | if (stream->in_free) 306 | return 1; 307 | 308 | stream->in_free++; 309 | 310 | /* if we are releasing the stream only (and preserving the underlying handle), 311 | * we need to do things a little differently. 312 | * We are only ever called like this when the stream is cast to a FILE* 313 | * for include (or other similar) purposes. 314 | * */ 315 | if (preserve_handle) { 316 | if (stream->fclose_stdiocast == PHP_STREAM_FCLOSE_FOPENCOOKIE) { 317 | /* If the stream was fopencookied, we must NOT touch anything 318 | * here, as the cookied stream relies on it all. 319 | * Instead, mark the stream as OK to auto-clean */ 320 | php_stream_auto_cleanup(stream); 321 | stream->in_free--; 322 | return 0; 323 | } 324 | /* otherwise, make sure that we don't close the FILE* from a cast */ 325 | release_cast = 0; 326 | } 327 | 328 | #if STREAM_DEBUG 329 | fprintf(stderr, "stream_free: %s:%p[%s] preserve_handle=%d release_cast=%d remove_rsrc=%d\n", 330 | stream->ops->label, stream, stream->__orig_path, preserve_handle, release_cast, remove_rsrc); 331 | #endif 332 | 333 | /* make sure everything is saved */ 334 | _php_stream_flush(stream, 1 TSRMLS_CC); 335 | 336 | /* If not called from the resource dtor, remove the stream 337 | * from the resource list. 338 | * */ 339 | if ((close_options & PHP_STREAM_FREE_RSRC_DTOR) == 0 && remove_rsrc) { 340 | zend_list_delete(stream->rsrc_id); 341 | } 342 | 343 | if (close_options & PHP_STREAM_FREE_CALL_DTOR) { 344 | if (release_cast && stream->fclose_stdiocast == PHP_STREAM_FCLOSE_FOPENCOOKIE) { 345 | /* calling fclose on an fopencookied stream will ultimately 346 | call this very same function. If we were called via fclose, 347 | the cookie_closer unsets the fclose_stdiocast flags, so 348 | we can be sure that we only reach here when PHP code calls 349 | php_stream_free. 350 | Lets let the cookie code clean it all up. 351 | */ 352 | stream->in_free = 0; 353 | return fclose(stream->stdiocast); 354 | } 355 | 356 | ret = stream->ops->close(stream, preserve_handle ? 0 : 1 TSRMLS_CC); 357 | stream->abstract = NULL; 358 | 359 | /* tidy up any FILE* that might have been fdopened */ 360 | if (release_cast && stream->fclose_stdiocast == PHP_STREAM_FCLOSE_FDOPEN && stream->stdiocast) { 361 | fclose(stream->stdiocast); 362 | stream->stdiocast = NULL; 363 | stream->fclose_stdiocast = PHP_STREAM_FCLOSE_NONE; 364 | } 365 | } 366 | 367 | if (close_options & PHP_STREAM_FREE_RELEASE_STREAM) { 368 | 369 | while (stream->filterhead) { 370 | php_stream_filter_remove_head(stream, 1); 371 | } 372 | 373 | if (stream->wrapper && stream->wrapper->wops && stream->wrapper->wops->stream_closer) { 374 | stream->wrapper->wops->stream_closer(stream->wrapper, stream TSRMLS_CC); 375 | stream->wrapper = NULL; 376 | } 377 | 378 | if (stream->wrapperdata) { 379 | zval_ptr_dtor(&stream->wrapperdata); 380 | stream->wrapperdata = NULL; 381 | } 382 | 383 | if (stream->readbuf) { 384 | pefree(stream->readbuf, stream->is_persistent); 385 | stream->readbuf = NULL; 386 | } 387 | 388 | if (stream->is_persistent && (close_options & PHP_STREAM_FREE_PERSISTENT)) { 389 | /* we don't work with *stream but need its value for comparison */ 390 | zend_hash_apply_with_argument(&EG(persistent_list), (apply_func_arg_t) _php_stream_free_persistent, stream TSRMLS_CC); 391 | } 392 | 393 | #if ZEND_DEBUG 394 | if ((close_options & PHP_STREAM_FREE_RSRC_DTOR) && (stream->__exposed == 0) && (EG(error_reporting) & E_WARNING)) { 395 | /* it leaked: Lets deliberately NOT pefree it so that the memory manager shows it 396 | * as leaked; it will log a warning, but lets help it out and display what kind 397 | * of stream it was. */ 398 | char leakbuf[512]; 399 | snprintf(leakbuf, sizeof(leakbuf), __FILE__ "(%d) : Stream of type '%s' 0x%08X (path:%s) was not closed\n", __LINE__, stream->ops->label, (unsigned int)stream, stream->__orig_path); 400 | 401 | if (stream->__orig_path) { 402 | pefree(stream->__orig_path, stream->is_persistent); 403 | stream->__orig_path = NULL; 404 | } 405 | 406 | # if defined(PHP_WIN32) 407 | OutputDebugString(leakbuf); 408 | # else 409 | fprintf(stderr, "%s", leakbuf); 410 | # endif 411 | } else { 412 | if (stream->__orig_path) { 413 | pefree(stream->__orig_path, stream->is_persistent); 414 | stream->__orig_path = NULL; 415 | } 416 | 417 | pefree(stream, stream->is_persistent); 418 | } 419 | #else 420 | pefree(stream, stream->is_persistent); 421 | #endif 422 | } 423 | 424 | return ret; 425 | } 426 | /* }}} */ 427 | 428 | /* {{{ filter API */ 429 | static HashTable stream_filters_hash; 430 | 431 | PHPAPI int php_stream_filter_register_factory(const char *filterpattern, php_stream_filter_factory *factory TSRMLS_DC) 432 | { 433 | return zend_hash_add(&stream_filters_hash, (char*)filterpattern, strlen(filterpattern), factory, sizeof(*factory), NULL); 434 | } 435 | 436 | PHPAPI int php_stream_filter_unregister_factory(const char *filterpattern TSRMLS_DC) 437 | { 438 | return zend_hash_del(&stream_filters_hash, (char*)filterpattern, strlen(filterpattern)); 439 | } 440 | 441 | /* We allow very simple pattern matching for filter factories: 442 | * if "charset.utf-8/sjis" is requested, we search first for an exact 443 | * match. If that fails, we try "charset.*". 444 | * This means that we don't need to clog up the hashtable with a zillion 445 | * charsets (for example) but still be able to provide them all as filters */ 446 | PHPAPI php_stream_filter *php_stream_filter_create(const char *filtername, const char *filterparams, int filterparamslen, int persistent TSRMLS_DC) 447 | { 448 | php_stream_filter_factory *factory = NULL; 449 | php_stream_filter *filter = NULL; 450 | int n; 451 | char *period; 452 | 453 | n = strlen(filtername); 454 | 455 | if (SUCCESS == zend_hash_find(&stream_filters_hash, (char*)filtername, n, (void**)&factory)) { 456 | filter = factory->create_filter(filtername, filterparams, filterparamslen, persistent TSRMLS_CC); 457 | } else if ((period = strchr(filtername, '.'))) { 458 | /* try a wildcard */ 459 | char wildname[128]; 460 | 461 | PHP_STRLCPY(wildname, filtername, sizeof(wildname) - 1, period-filtername + 1); 462 | strcat(wildname, "*"); 463 | 464 | if (SUCCESS == zend_hash_find(&stream_filters_hash, wildname, strlen(wildname), (void**)&factory)) { 465 | filter = factory->create_filter(filtername, filterparams, filterparamslen, persistent TSRMLS_CC); 466 | } 467 | } 468 | 469 | if (filter == NULL) { 470 | /* TODO: these need correct docrefs */ 471 | if (factory == NULL) 472 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to locate filter \"%s\"", filtername); 473 | else 474 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to create or locate filter \"%s\"", filtername); 475 | } 476 | 477 | return filter; 478 | } 479 | 480 | PHPAPI php_stream_filter *_php_stream_filter_alloc(php_stream_filter_ops *fops, void *abstract, int persistent STREAMS_DC TSRMLS_DC) 481 | { 482 | php_stream_filter *filter; 483 | 484 | filter = (php_stream_filter*) pemalloc_rel_orig(sizeof(php_stream_filter), persistent); 485 | memset(filter, 0, sizeof(php_stream_filter)); 486 | 487 | filter->fops = fops; 488 | filter->abstract = abstract; 489 | filter->is_persistent = persistent; 490 | 491 | return filter; 492 | } 493 | 494 | PHPAPI void php_stream_filter_free(php_stream_filter *filter TSRMLS_DC) 495 | { 496 | if (filter->fops->dtor) 497 | filter->fops->dtor(filter TSRMLS_CC); 498 | pefree(filter, filter->is_persistent); 499 | } 500 | 501 | PHPAPI void php_stream_filter_prepend(php_stream *stream, php_stream_filter *filter) 502 | { 503 | filter->next = stream->filterhead; 504 | filter->prev = NULL; 505 | 506 | if (stream->filterhead) { 507 | stream->filterhead->prev = filter; 508 | } else { 509 | stream->filtertail = filter; 510 | } 511 | stream->filterhead = filter; 512 | filter->stream = stream; 513 | } 514 | 515 | PHPAPI void php_stream_filter_append(php_stream *stream, php_stream_filter *filter) 516 | { 517 | filter->prev = stream->filtertail; 518 | filter->next = NULL; 519 | if (stream->filtertail) { 520 | stream->filtertail->next = filter; 521 | } else { 522 | stream->filterhead = filter; 523 | } 524 | stream->filtertail = filter; 525 | filter->stream = stream; 526 | } 527 | 528 | PHPAPI php_stream_filter *php_stream_filter_remove(php_stream *stream, php_stream_filter *filter, int call_dtor TSRMLS_DC) 529 | { 530 | assert(stream == filter->stream); 531 | 532 | if (filter->prev) { 533 | filter->prev->next = filter->next; 534 | } else { 535 | stream->filterhead = filter->next; 536 | } 537 | if (filter->next) { 538 | filter->next->prev = filter->prev; 539 | } else { 540 | stream->filtertail = filter->prev; 541 | } 542 | if (call_dtor) { 543 | php_stream_filter_free(filter TSRMLS_CC); 544 | return NULL; 545 | } 546 | return filter; 547 | } 548 | /* }}} */ 549 | 550 | /* {{{ generic stream operations */ 551 | 552 | static void php_stream_fill_read_buffer(php_stream *stream, size_t size TSRMLS_DC) 553 | { 554 | /* allocate/fill the buffer */ 555 | size_t justread = 0; 556 | 557 | /* is there enough data in the buffer ? */ 558 | if (stream->writepos - stream->readpos < (off_t)size) { 559 | 560 | /* ignore eof here; the underlying state might have changed */ 561 | 562 | /* no; so lets fetch more data */ 563 | 564 | /* reduce buffer memory consumption if possible, to avoid a realloc */ 565 | if (stream->readbuf && stream->readbuflen - stream->writepos < stream->chunk_size) { 566 | memmove(stream->readbuf, stream->readbuf + stream->readpos, stream->readbuflen - stream->readpos); 567 | stream->writepos -= stream->readpos; 568 | stream->readpos = 0; 569 | } 570 | 571 | /* grow the buffer if required */ 572 | if (stream->readbuflen - stream->writepos < stream->chunk_size) { 573 | stream->readbuflen += stream->chunk_size; 574 | stream->readbuf = perealloc(stream->readbuf, stream->readbuflen, 575 | stream->is_persistent); 576 | } 577 | 578 | if (stream->filterhead) { 579 | justread = stream->filterhead->fops->read(stream, stream->filterhead, 580 | stream->readbuf + stream->writepos, 581 | stream->readbuflen - stream->writepos 582 | TSRMLS_CC); 583 | } else { 584 | justread = stream->ops->read(stream, stream->readbuf + stream->writepos, 585 | stream->readbuflen - stream->writepos 586 | TSRMLS_CC); 587 | } 588 | 589 | if (justread != (size_t)-1) { 590 | stream->writepos += justread; 591 | } 592 | } 593 | } 594 | 595 | PHPAPI size_t _php_stream_read(php_stream *stream, char *buf, size_t size TSRMLS_DC) 596 | { 597 | size_t toread = 0, didread = 0; 598 | 599 | while (size > 0) { 600 | 601 | /* take from the read buffer first. 602 | * It is possible that a buffered stream was switched to non-buffered, so we 603 | * drain the remainder of the buffer before using the "raw" read mode for 604 | * the excess */ 605 | if (stream->writepos > stream->readpos) { 606 | 607 | toread = stream->writepos - stream->readpos; 608 | if (toread > size) 609 | toread = size; 610 | 611 | memcpy(buf, stream->readbuf + stream->readpos, toread); 612 | stream->readpos += toread; 613 | size -= toread; 614 | buf += toread; 615 | didread += toread; 616 | } 617 | 618 | /* ignore eof here; the underlying state might have changed */ 619 | if (size == 0) { 620 | break; 621 | } 622 | 623 | if (stream->flags & PHP_STREAM_FLAG_NO_BUFFER || stream->chunk_size == 1) { 624 | if (stream->filterhead) { 625 | toread = stream->filterhead->fops->read(stream, stream->filterhead, 626 | buf, size 627 | TSRMLS_CC); 628 | } else { 629 | toread = stream->ops->read(stream, buf, size TSRMLS_CC); 630 | } 631 | } else { 632 | php_stream_fill_read_buffer(stream, size TSRMLS_CC); 633 | 634 | toread = stream->writepos - stream->readpos; 635 | if (toread > size) 636 | toread = size; 637 | 638 | if (toread > 0) { 639 | memcpy(buf, stream->readbuf + stream->readpos, toread); 640 | stream->readpos += toread; 641 | } 642 | } 643 | if (toread > 0) { 644 | didread += toread; 645 | buf += toread; 646 | size -= toread; 647 | } else { 648 | /* EOF, or temporary end of data (for non-blocking mode). */ 649 | break; 650 | } 651 | 652 | if (stream->flags & PHP_STREAM_FLAG_AVOID_BLOCKING) { 653 | break; 654 | } 655 | 656 | /* just break anyway, to avoid greedy read */ 657 | if (stream->wrapper != &php_plain_files_wrapper) { 658 | break; 659 | } 660 | } 661 | 662 | if (didread > 0) 663 | stream->position += didread; 664 | 665 | return didread; 666 | } 667 | 668 | PHPAPI int _php_stream_eof(php_stream *stream TSRMLS_DC) 669 | { 670 | /* if there is data in the buffer, it's not EOF */ 671 | if (stream->writepos - stream->readpos > 0) 672 | return 0; 673 | 674 | if (!stream->eof && php_stream_is(stream, PHP_STREAM_IS_SOCKET)) { 675 | stream->eof = !_php_network_is_stream_alive(stream TSRMLS_CC); 676 | } 677 | 678 | return stream->eof; 679 | } 680 | 681 | PHPAPI int _php_stream_putc(php_stream *stream, int c TSRMLS_DC) 682 | { 683 | unsigned char buf = c; 684 | 685 | if (php_stream_write(stream, &buf, 1) > 0) { 686 | return 1; 687 | } 688 | return EOF; 689 | } 690 | 691 | PHPAPI int _php_stream_getc(php_stream *stream TSRMLS_DC) 692 | { 693 | unsigned char buf; 694 | 695 | if (php_stream_read(stream, &buf, 1) > 0) { 696 | return buf & 0xff; 697 | } 698 | return EOF; 699 | } 700 | 701 | PHPAPI int _php_stream_puts(php_stream *stream, char *buf TSRMLS_DC) 702 | { 703 | int len; 704 | char newline[2] = "\n"; /* is this OK for Win? */ 705 | len = strlen(buf); 706 | 707 | if (len > 0 && php_stream_write(stream, buf, len) && php_stream_write(stream, newline, 1)) { 708 | return 1; 709 | } 710 | return 0; 711 | } 712 | 713 | PHPAPI int _php_stream_stat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC) 714 | { 715 | memset(ssb, 0, sizeof(*ssb)); 716 | 717 | /* if the stream was wrapped, allow the wrapper to stat it */ 718 | if (stream->wrapper && stream->wrapper->wops->stream_stat != NULL) { 719 | return stream->wrapper->wops->stream_stat(stream->wrapper, stream, ssb TSRMLS_CC); 720 | } 721 | 722 | /* if the stream doesn't directly support stat-ing, return with failure. 723 | * We could try and emulate this by casting to a FD and fstat-ing it, 724 | * but since the fd might not represent the actual underlying content 725 | * this would give bogus results. */ 726 | if (stream->ops->stat == NULL) { 727 | return -1; 728 | } 729 | 730 | return (stream->ops->stat)(stream, ssb TSRMLS_CC); 731 | } 732 | 733 | PHPAPI char *php_stream_locate_eol(php_stream *stream, char *buf, size_t buf_len TSRMLS_DC) 734 | { 735 | size_t avail; 736 | char *cr, *lf, *eol = NULL; 737 | char *readptr; 738 | 739 | if (!buf) { 740 | readptr = stream->readbuf + stream->readpos; 741 | avail = stream->writepos - stream->readpos; 742 | } else { 743 | readptr = buf; 744 | avail = buf_len; 745 | } 746 | 747 | /* Look for EOL */ 748 | if (stream->flags & PHP_STREAM_FLAG_DETECT_EOL) { 749 | cr = memchr(readptr, '\r', avail); 750 | lf = memchr(readptr, '\n', avail); 751 | 752 | if (cr && lf != cr + 1 && !(lf && lf < cr)) { 753 | /* mac */ 754 | stream->flags ^= PHP_STREAM_FLAG_DETECT_EOL; 755 | stream->flags |= PHP_STREAM_FLAG_EOL_MAC; 756 | eol = cr; 757 | } else if ((cr && lf && cr == lf - 1) || (lf)) { 758 | /* dos or unix endings */ 759 | stream->flags ^= PHP_STREAM_FLAG_DETECT_EOL; 760 | eol = lf; 761 | } 762 | } else if (stream->flags & PHP_STREAM_FLAG_EOL_MAC) { 763 | eol = memchr(readptr, '\r', avail); 764 | } else { 765 | /* unix (and dos) line endings */ 766 | eol = memchr(readptr, '\n', avail); 767 | } 768 | 769 | return eol; 770 | } 771 | 772 | /* If buf == NULL, the buffer will be allocated automatically and will be of an 773 | * appropriate length to hold the line, regardless of the line length, memory 774 | * permitting */ 775 | PHPAPI char *_php_stream_get_line(php_stream *stream, char *buf, size_t maxlen, 776 | size_t *returned_len TSRMLS_DC) 777 | { 778 | size_t avail = 0; 779 | size_t current_buf_size = 0; 780 | size_t total_copied = 0; 781 | int grow_mode = 0; 782 | char *bufstart = buf; 783 | 784 | if (buf == NULL) 785 | grow_mode = 1; 786 | else if (maxlen == 0) 787 | return NULL; 788 | 789 | /* 790 | * If the underlying stream operations block when no new data is readable, 791 | * we need to take extra precautions. 792 | * 793 | * If there is buffered data available, we check for a EOL. If it exists, 794 | * we pass the data immediately back to the caller. This saves a call 795 | * to the read implementation and will not block where blocking 796 | * is not necessary at all. 797 | * 798 | * If the stream buffer contains more data than the caller requested, 799 | * we can also avoid that costly step and simply return that data. 800 | */ 801 | 802 | for (;;) { 803 | avail = stream->writepos - stream->readpos; 804 | 805 | if (avail > 0) { 806 | size_t cpysz = 0; 807 | char *readptr; 808 | char *eol; 809 | int done = 0; 810 | 811 | readptr = stream->readbuf + stream->readpos; 812 | eol = php_stream_locate_eol(stream, NULL, 0 TSRMLS_CC); 813 | 814 | if (eol) { 815 | cpysz = eol - readptr + 1; 816 | done = 1; 817 | } else { 818 | cpysz = avail; 819 | } 820 | 821 | if (grow_mode) { 822 | /* allow room for a NUL. If this realloc is really a realloc 823 | * (ie: second time around), we get an extra byte. In most 824 | * cases, with the default chunk size of 8K, we will only 825 | * incur that overhead once. When people have lines longer 826 | * than 8K, we waste 1 byte per additional 8K or so. 827 | * That seems acceptable to me, to avoid making this code 828 | * hard to follow */ 829 | bufstart = erealloc(bufstart, current_buf_size + cpysz + 1); 830 | current_buf_size += cpysz + 1; 831 | buf = bufstart + total_copied; 832 | } else { 833 | if (cpysz >= maxlen - 1) { 834 | cpysz = maxlen - 1; 835 | done = 1; 836 | } 837 | } 838 | 839 | memcpy(buf, readptr, cpysz); 840 | 841 | stream->position += cpysz; 842 | stream->readpos += cpysz; 843 | buf += cpysz; 844 | maxlen -= cpysz; 845 | total_copied += cpysz; 846 | 847 | if (done) { 848 | break; 849 | } 850 | } else if (stream->eof) { 851 | break; 852 | } else { 853 | /* XXX: Should be fine to always read chunk_size */ 854 | size_t toread; 855 | 856 | if (grow_mode) { 857 | toread = stream->chunk_size; 858 | } else { 859 | toread = maxlen - 1; 860 | if (toread > stream->chunk_size) 861 | toread = stream->chunk_size; 862 | } 863 | 864 | php_stream_fill_read_buffer(stream, toread TSRMLS_CC); 865 | 866 | if (stream->writepos - stream->readpos == 0) { 867 | break; 868 | } 869 | } 870 | } 871 | 872 | if (total_copied == 0) { 873 | if (grow_mode) { 874 | assert(bufstart == NULL); 875 | } 876 | return NULL; 877 | } 878 | 879 | buf[0] = '\0'; 880 | if (returned_len) 881 | *returned_len = total_copied; 882 | 883 | return bufstart; 884 | } 885 | 886 | PHPAPI int _php_stream_flush(php_stream *stream, int closing TSRMLS_DC) 887 | { 888 | int ret = 0; 889 | 890 | if (stream->filterhead) 891 | stream->filterhead->fops->flush(stream, stream->filterhead, closing TSRMLS_CC); 892 | 893 | if (stream->ops->flush) { 894 | ret = stream->ops->flush(stream TSRMLS_CC); 895 | } 896 | 897 | return ret; 898 | } 899 | 900 | PHPAPI size_t _php_stream_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) 901 | { 902 | size_t didwrite = 0, towrite, justwrote; 903 | 904 | assert(stream); 905 | if (buf == NULL || count == 0 || stream->ops->write == NULL) 906 | return 0; 907 | 908 | /* if we have a seekable stream we need to ensure that data is written at the 909 | * current stream->position. This means invalidating the read buffer and then 910 | * performing a low-level seek */ 911 | if (stream->ops->seek && (stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0 && stream->writepos > stream->readpos) { 912 | stream->readpos = stream->writepos = 0; 913 | 914 | stream->ops->seek(stream, stream->position, SEEK_SET, &stream->position TSRMLS_CC); 915 | } 916 | 917 | while (count > 0) { 918 | towrite = count; 919 | if (towrite > stream->chunk_size) 920 | towrite = stream->chunk_size; 921 | 922 | if (stream->filterhead) { 923 | justwrote = stream->filterhead->fops->write(stream, stream->filterhead, buf, towrite TSRMLS_CC); 924 | } else { 925 | justwrote = stream->ops->write(stream, buf, towrite TSRMLS_CC); 926 | } 927 | /* convert justwrote to an integer, since normally it is unsigned */ 928 | if ((int)justwrote > 0) { 929 | buf += justwrote; 930 | count -= justwrote; 931 | didwrite += justwrote; 932 | 933 | /* Only screw with the buffer if we can seek, otherwise we lose data 934 | * buffered from fifos and sockets */ 935 | if (stream->ops->seek && (stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0) { 936 | stream->position += justwrote; 937 | } 938 | } else { 939 | break; 940 | } 941 | } 942 | return didwrite; 943 | } 944 | 945 | PHPAPI size_t _php_stream_printf(php_stream *stream TSRMLS_DC, const char *fmt, ...) 946 | { 947 | size_t count; 948 | char *buf; 949 | va_list ap; 950 | 951 | va_start(ap, fmt); 952 | count = vspprintf(&buf, 0, fmt, ap); 953 | va_end(ap); 954 | 955 | if (!buf) 956 | return 0; /* error condition */ 957 | 958 | count = php_stream_write(stream, buf, count); 959 | efree(buf); 960 | 961 | return count; 962 | } 963 | 964 | PHPAPI off_t _php_stream_tell(php_stream *stream TSRMLS_DC) 965 | { 966 | return stream->position; 967 | } 968 | 969 | PHPAPI int _php_stream_seek(php_stream *stream, off_t offset, int whence TSRMLS_DC) 970 | { 971 | /* handle the case where we are in the buffer */ 972 | if ((stream->flags & PHP_STREAM_FLAG_NO_BUFFER) == 0) { 973 | switch(whence) { 974 | case SEEK_CUR: 975 | if (offset > 0 && offset < stream->writepos - stream->readpos) { 976 | stream->readpos += offset; 977 | stream->position += offset; 978 | stream->eof = 0; 979 | return 0; 980 | } 981 | break; 982 | case SEEK_SET: 983 | if (offset > stream->position && 984 | offset < stream->position + stream->writepos - stream->readpos) { 985 | stream->readpos += offset - stream->position; 986 | stream->position = offset; 987 | stream->eof = 0; 988 | return 0; 989 | } 990 | break; 991 | } 992 | } 993 | 994 | if (stream->ops->seek && (stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0) { 995 | int ret; 996 | 997 | if (stream->filterhead) 998 | stream->filterhead->fops->flush(stream, stream->filterhead, 0 TSRMLS_CC); 999 | 1000 | switch(whence) { 1001 | case SEEK_CUR: 1002 | offset = stream->position + offset; 1003 | whence = SEEK_SET; 1004 | break; 1005 | } 1006 | ret = stream->ops->seek(stream, offset, whence, &stream->position TSRMLS_CC); 1007 | 1008 | if (((stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0) || ret == 0) { 1009 | if (ret == 0) 1010 | stream->eof = 0; 1011 | 1012 | /* invalidate the buffer contents */ 1013 | stream->readpos = stream->writepos = 0; 1014 | 1015 | return ret; 1016 | } 1017 | /* else the stream has decided that it can't support seeking after all; 1018 | * fall through to attempt emulation */ 1019 | } 1020 | 1021 | /* emulate forward moving seeks with reads */ 1022 | if (whence == SEEK_CUR && offset > 0) { 1023 | char tmp[1024]; 1024 | while(offset >= sizeof(tmp)) { 1025 | if (php_stream_read(stream, tmp, sizeof(tmp)) == 0) 1026 | return -1; 1027 | offset -= sizeof(tmp); 1028 | } 1029 | if (offset) { 1030 | if (php_stream_read(stream, tmp, offset) == 0) 1031 | return -1; 1032 | } 1033 | stream->eof = 0; 1034 | return 0; 1035 | } 1036 | 1037 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "stream does not support seeking"); 1038 | 1039 | return -1; 1040 | } 1041 | 1042 | PHPAPI int _php_stream_set_option(php_stream *stream, int option, int value, void *ptrparam TSRMLS_DC) 1043 | { 1044 | int ret = PHP_STREAM_OPTION_RETURN_NOTIMPL; 1045 | 1046 | if (stream->ops->set_option) { 1047 | ret = stream->ops->set_option(stream, option, value, ptrparam TSRMLS_CC); 1048 | } 1049 | 1050 | if (ret == PHP_STREAM_OPTION_RETURN_NOTIMPL) { 1051 | switch(option) { 1052 | case PHP_STREAM_OPTION_SET_CHUNK_SIZE: 1053 | ret = stream->chunk_size; 1054 | stream->chunk_size = value; 1055 | return ret; 1056 | 1057 | case PHP_STREAM_OPTION_READ_BUFFER: 1058 | /* try to match the buffer mode as best we can */ 1059 | if (value == PHP_STREAM_BUFFER_NONE) { 1060 | stream->flags |= PHP_STREAM_FLAG_NO_BUFFER; 1061 | } else { 1062 | stream->flags ^= PHP_STREAM_FLAG_NO_BUFFER; 1063 | } 1064 | ret = PHP_STREAM_OPTION_RETURN_OK; 1065 | break; 1066 | 1067 | default: 1068 | ret = PHP_STREAM_OPTION_RETURN_ERR; 1069 | } 1070 | } 1071 | 1072 | return ret; 1073 | } 1074 | 1075 | PHPAPI size_t _php_stream_passthru(php_stream * stream STREAMS_DC TSRMLS_DC) 1076 | { 1077 | size_t bcount = 0; 1078 | int ready = 0; 1079 | char buf[8192]; 1080 | #ifdef HAVE_MMAP 1081 | int fd; 1082 | #endif 1083 | 1084 | #ifdef HAVE_MMAP 1085 | if (!php_stream_is(stream, PHP_STREAM_IS_SOCKET) 1086 | && stream->filterhead == NULL 1087 | && php_stream_tell(stream) == 0 1088 | && SUCCESS == php_stream_cast(stream, PHP_STREAM_AS_FD, (void*)&fd, 0)) 1089 | { 1090 | struct stat sbuf; 1091 | off_t off; 1092 | void *p; 1093 | size_t len; 1094 | 1095 | fstat(fd, &sbuf); 1096 | 1097 | if (sbuf.st_size > sizeof(buf)) { 1098 | off = php_stream_tell(stream); 1099 | len = sbuf.st_size - off; 1100 | p = mmap(0, len, PROT_READ, MAP_SHARED, fd, off); 1101 | if (p != (void *) MAP_FAILED) { 1102 | BG(mmap_file) = p; 1103 | BG(mmap_len) = len; 1104 | PHPWRITE(p, len); 1105 | BG(mmap_file) = NULL; 1106 | munmap(p, len); 1107 | bcount += len; 1108 | ready = 1; 1109 | } 1110 | } 1111 | } 1112 | #endif 1113 | if(!ready) { 1114 | int b; 1115 | 1116 | while ((b = php_stream_read(stream, buf, sizeof(buf))) > 0) { 1117 | PHPWRITE(buf, b); 1118 | bcount += b; 1119 | } 1120 | } 1121 | return bcount; 1122 | } 1123 | 1124 | 1125 | PHPAPI size_t _php_stream_copy_to_mem(php_stream *src, char **buf, size_t maxlen, int persistent STREAMS_DC TSRMLS_DC) 1126 | { 1127 | size_t ret = 0; 1128 | char *ptr; 1129 | size_t len = 0, max_len; 1130 | int step = CHUNK_SIZE; 1131 | int min_room = CHUNK_SIZE / 4; 1132 | php_stream_statbuf ssbuf; 1133 | #if HAVE_MMAP 1134 | int srcfd; 1135 | #endif 1136 | 1137 | if (buf) 1138 | *buf = NULL; 1139 | 1140 | if (maxlen == 0) 1141 | return 0; 1142 | 1143 | if (maxlen == PHP_STREAM_COPY_ALL) 1144 | maxlen = 0; 1145 | 1146 | #if HAVE_MMAP 1147 | /* try and optimize the case where we are copying from the start of a plain file. 1148 | * We could probably make this work in more situations, but I don't trust the stdio 1149 | * buffering layer. 1150 | * */ 1151 | if ( php_stream_is(src, PHP_STREAM_IS_STDIO) && 1152 | src->filterhead == NULL && 1153 | php_stream_tell(src) == 0 && 1154 | SUCCESS == php_stream_cast(src, PHP_STREAM_AS_FD, (void**)&srcfd, 0)) 1155 | { 1156 | struct stat sbuf; 1157 | 1158 | if (fstat(srcfd, &sbuf) == 0) { 1159 | void *srcfile; 1160 | 1161 | #if STREAM_DEBUG 1162 | fprintf(stderr, "mmap attempt: maxlen=%d filesize=%ld\n", maxlen, sbuf.st_size); 1163 | #endif 1164 | 1165 | if (maxlen > sbuf.st_size || maxlen == 0) 1166 | maxlen = sbuf.st_size; 1167 | #if STREAM_DEBUG 1168 | fprintf(stderr, "mmap attempt: will map maxlen=%d\n", maxlen); 1169 | #endif 1170 | 1171 | srcfile = mmap(NULL, maxlen, PROT_READ, MAP_SHARED, srcfd, 0); 1172 | if (srcfile != (void*)MAP_FAILED) { 1173 | 1174 | *buf = pemalloc_rel_orig(maxlen + 1, persistent); 1175 | 1176 | if (*buf) { 1177 | memcpy(*buf, srcfile, maxlen); 1178 | (*buf)[maxlen] = '\0'; 1179 | ret = maxlen; 1180 | } 1181 | 1182 | munmap(srcfile, maxlen); 1183 | 1184 | return ret; 1185 | } 1186 | } 1187 | /* fall through - we might be able to copy in smaller chunks */ 1188 | } 1189 | #endif 1190 | 1191 | /* avoid many reallocs by allocating a good sized chunk to begin with, if 1192 | * we can. Note that the stream may be filtered, in which case the stat 1193 | * result may be inaccurate, as the filter may inflate or deflate the 1194 | * number of bytes that we can read. In order to avoid an upsize followed 1195 | * by a downsize of the buffer, overestimate by the step size (which is 1196 | * 2K). */ 1197 | if (php_stream_stat(src, &ssbuf) == 0 && ssbuf.sb.st_size > 0) { 1198 | max_len = ssbuf.sb.st_size + step; 1199 | } else { 1200 | max_len = step; 1201 | } 1202 | 1203 | ptr = *buf = pemalloc_rel_orig(max_len, persistent); 1204 | 1205 | while((ret = php_stream_read(src, ptr, max_len - len))) { 1206 | len += ret; 1207 | if (len + min_room >= max_len) { 1208 | *buf = perealloc_rel_orig(*buf, max_len + step, persistent); 1209 | max_len += step; 1210 | ptr = *buf + len; 1211 | } else { 1212 | ptr += ret; 1213 | } 1214 | } 1215 | if (len) { 1216 | *buf = perealloc_rel_orig(*buf, len + 1, persistent); 1217 | (*buf)[len] = '\0'; 1218 | } else { 1219 | pefree(*buf, persistent); 1220 | *buf = NULL; 1221 | } 1222 | return len; 1223 | } 1224 | 1225 | PHPAPI size_t _php_stream_copy_to_stream(php_stream *src, php_stream *dest, size_t maxlen STREAMS_DC TSRMLS_DC) 1226 | { 1227 | char buf[CHUNK_SIZE]; 1228 | size_t readchunk; 1229 | size_t haveread = 0; 1230 | size_t didread; 1231 | php_stream_statbuf ssbuf; 1232 | #if HAVE_MMAP 1233 | int srcfd; 1234 | #endif 1235 | 1236 | if (maxlen == 0) 1237 | return 0; 1238 | 1239 | if (maxlen == PHP_STREAM_COPY_ALL) 1240 | maxlen = 0; 1241 | 1242 | #if HAVE_MMAP 1243 | /* try and optimize the case where we are copying from the start of a plain file. 1244 | * We could probably make this work in more situations, but I don't trust the stdio 1245 | * buffering layer. 1246 | * */ 1247 | if ( php_stream_is(src, PHP_STREAM_IS_STDIO) && 1248 | src->filterhead == NULL && 1249 | php_stream_tell(src) == 0 && 1250 | SUCCESS == php_stream_cast(src, PHP_STREAM_AS_FD, (void**)&srcfd, 0)) 1251 | { 1252 | struct stat sbuf; 1253 | 1254 | if (fstat(srcfd, &sbuf) == 0) { 1255 | void *srcfile; 1256 | 1257 | /* in the event that the source file is 0 bytes, return 1 to indicate success 1258 | * because opening the file to write had already created a copy */ 1259 | 1260 | if(sbuf.st_size ==0) 1261 | return 1; 1262 | 1263 | if (maxlen > sbuf.st_size || maxlen == 0) 1264 | maxlen = sbuf.st_size; 1265 | 1266 | srcfile = mmap(NULL, maxlen, PROT_READ, MAP_SHARED, srcfd, 0); 1267 | if (srcfile != (void*)MAP_FAILED) { 1268 | haveread = php_stream_write(dest, srcfile, maxlen); 1269 | munmap(srcfile, maxlen); 1270 | return haveread; 1271 | } 1272 | } 1273 | /* fall through - we might be able to copy in smaller chunks */ 1274 | } 1275 | #endif 1276 | 1277 | if (php_stream_stat(src, &ssbuf) == 0) { 1278 | /* in the event that the source file is 0 bytes, return 1 to indicate success 1279 | * because opening the file to write had already created a copy */ 1280 | if (ssbuf.sb.st_size == 0 1281 | #ifdef S_ISFIFO 1282 | && !S_ISFIFO(ssbuf.sb.st_mode) 1283 | #endif 1284 | #ifdef S_ISCHR 1285 | && !S_ISCHR(ssbuf.sb.st_mode) 1286 | #endif 1287 | ) { 1288 | return 1; 1289 | } 1290 | } 1291 | 1292 | while(1) { 1293 | readchunk = sizeof(buf); 1294 | 1295 | if (maxlen && (maxlen - haveread) < readchunk) 1296 | readchunk = maxlen - haveread; 1297 | 1298 | didread = php_stream_read(src, buf, readchunk); 1299 | 1300 | if (didread) { 1301 | /* extra paranoid */ 1302 | size_t didwrite, towrite; 1303 | char *writeptr; 1304 | 1305 | towrite = didread; 1306 | writeptr = buf; 1307 | haveread += didread; 1308 | 1309 | while(towrite) { 1310 | didwrite = php_stream_write(dest, writeptr, towrite); 1311 | if (didwrite == 0) 1312 | return 0; /* error */ 1313 | 1314 | towrite -= didwrite; 1315 | writeptr += didwrite; 1316 | } 1317 | } else { 1318 | if (maxlen == 0) { 1319 | return haveread; 1320 | } else { 1321 | return 0; /* error */ 1322 | } 1323 | } 1324 | 1325 | if (maxlen - haveread == 0) { 1326 | break; 1327 | } 1328 | } 1329 | return haveread; 1330 | 1331 | } 1332 | /* }}} */ 1333 | 1334 | /* {{{ ------- STDIO stream implementation -------*/ 1335 | 1336 | typedef struct { 1337 | FILE *file; 1338 | int fd; /* underlying file descriptor */ 1339 | int is_process_pipe; /* use pclose instead of fclose */ 1340 | int is_pipe; /* don't try and seek */ 1341 | char *temp_file_name; /* if non-null, this is the path to a temporary file that 1342 | * is to be deleted when the stream is closed */ 1343 | #if HAVE_FLUSHIO 1344 | char last_op; 1345 | #endif 1346 | } php_stdio_stream_data; 1347 | 1348 | PHPAPI php_stream *_php_stream_fopen_temporary_file(const char *dir, const char *pfx, char **opened_path STREAMS_DC TSRMLS_DC) 1349 | { 1350 | int fd = php_open_temporary_fd(dir, pfx, opened_path TSRMLS_CC); 1351 | 1352 | if (fd != -1) { 1353 | php_stream *stream = php_stream_fopen_from_fd_rel(fd, "r+b", NULL); 1354 | if (stream) { 1355 | return stream; 1356 | } 1357 | close(fd); 1358 | 1359 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to allocate stream"); 1360 | 1361 | return NULL; 1362 | } 1363 | return NULL; 1364 | } 1365 | 1366 | PHPAPI php_stream *_php_stream_fopen_tmpfile(int dummy STREAMS_DC TSRMLS_DC) 1367 | { 1368 | char *opened_path = NULL; 1369 | int fd = php_open_temporary_fd(NULL, "php", &opened_path TSRMLS_CC); 1370 | 1371 | if (fd != -1) { 1372 | php_stream *stream = php_stream_fopen_from_fd_rel(fd, "r+b", NULL); 1373 | if (stream) { 1374 | php_stdio_stream_data *self = (php_stdio_stream_data*)stream->abstract; 1375 | stream->wrapper = &php_plain_files_wrapper; 1376 | 1377 | self->temp_file_name = opened_path; 1378 | return stream; 1379 | } 1380 | close(fd); 1381 | 1382 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to allocate stream"); 1383 | 1384 | return NULL; 1385 | } 1386 | return NULL; 1387 | } 1388 | 1389 | 1390 | 1391 | PHPAPI php_stream *_php_stream_fopen_from_file(FILE *file, const char *mode STREAMS_DC TSRMLS_DC) 1392 | { 1393 | php_stdio_stream_data *self; 1394 | php_stream *stream; 1395 | 1396 | self = emalloc_rel_orig(sizeof(*self)); 1397 | self->file = file; 1398 | self->is_pipe = 0; 1399 | self->is_process_pipe = 0; 1400 | self->temp_file_name = NULL; 1401 | self->fd = fileno(file); 1402 | 1403 | #ifdef S_ISFIFO 1404 | /* detect if this is a pipe */ 1405 | if (self->fd >= 0) { 1406 | struct stat sb; 1407 | self->is_pipe = (fstat(self->fd, &sb) == 0 && S_ISFIFO(sb.st_mode)) ? 1 : 0; 1408 | } 1409 | #endif 1410 | 1411 | stream = php_stream_alloc_rel(&php_stream_stdio_ops, self, 0, mode); 1412 | 1413 | #ifdef HAVE_BROKEN_GLIBC_FOPEN_APPEND 1414 | if (strchr(mode, 'a')) { 1415 | fseek(file, 0, SEEK_END); 1416 | } 1417 | #endif 1418 | 1419 | if (stream) { 1420 | if (self->is_pipe) { 1421 | stream->flags |= PHP_STREAM_FLAG_NO_SEEK | PHP_STREAM_FLAG_AVOID_BLOCKING; 1422 | } else { 1423 | stream->position = ftell(file); 1424 | } 1425 | } 1426 | 1427 | return stream; 1428 | } 1429 | 1430 | PHPAPI php_stream *_php_stream_fopen_from_pipe(FILE *file, const char *mode STREAMS_DC TSRMLS_DC) 1431 | { 1432 | php_stdio_stream_data *self; 1433 | php_stream *stream; 1434 | 1435 | self = emalloc_rel_orig(sizeof(*self)); 1436 | self->file = file; 1437 | self->is_pipe = 1; 1438 | self->is_process_pipe = 1; 1439 | self->fd = fileno(file); 1440 | self->temp_file_name = NULL; 1441 | 1442 | stream = php_stream_alloc_rel(&php_stream_stdio_ops, self, 0, mode); 1443 | stream->flags |= PHP_STREAM_FLAG_NO_SEEK | PHP_STREAM_FLAG_AVOID_BLOCKING; 1444 | return stream; 1445 | } 1446 | 1447 | static size_t php_stdiop_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) 1448 | { 1449 | php_stdio_stream_data *data = (php_stdio_stream_data*)stream->abstract; 1450 | 1451 | assert(data != NULL); 1452 | 1453 | if (data->fd >= 0) { 1454 | int bytes_written = write(data->fd, buf, count); 1455 | if (bytes_written < 0) return 0; 1456 | return (size_t) bytes_written; 1457 | } else { 1458 | 1459 | #if HAVE_FLUSHIO 1460 | if (!data->is_pipe && data->last_op == 'r') { 1461 | fseek(data->file, 0, SEEK_CUR); 1462 | } 1463 | data->last_op = 'w'; 1464 | #endif 1465 | 1466 | return fwrite(buf, 1, count, data->file); 1467 | } 1468 | } 1469 | 1470 | static size_t php_stdiop_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) 1471 | { 1472 | php_stdio_stream_data *data = (php_stdio_stream_data*)stream->abstract; 1473 | int ret; 1474 | 1475 | assert(data != NULL); 1476 | 1477 | if (data->fd >= 0) { 1478 | ret = read(data->fd, buf, count); 1479 | 1480 | stream->eof = (ret == 0 || (ret == -1 && errno != EWOULDBLOCK)); 1481 | 1482 | } else { 1483 | #if HAVE_FLUSHIO 1484 | if (!data->is_pipe && data->last_op == 'w') 1485 | fseek(data->file, 0, SEEK_CUR); 1486 | data->last_op = 'r'; 1487 | #endif 1488 | 1489 | ret = fread(buf, 1, count, data->file); 1490 | 1491 | stream->eof = feof(data->file); 1492 | } 1493 | return ret < 0 ? 0 : ret; 1494 | } 1495 | 1496 | static int php_stdiop_close(php_stream *stream, int close_handle TSRMLS_DC) 1497 | { 1498 | int ret; 1499 | php_stdio_stream_data *data = (php_stdio_stream_data*)stream->abstract; 1500 | 1501 | assert(data != NULL); 1502 | 1503 | if (close_handle) { 1504 | if (data->file) { 1505 | if (data->is_process_pipe) { 1506 | errno = 0; 1507 | ret = pclose(data->file); 1508 | 1509 | #if HAVE_SYS_WAIT_H 1510 | if (WIFEXITED(ret)) { 1511 | ret = WEXITSTATUS(ret); 1512 | } 1513 | #endif 1514 | } else { 1515 | ret = fclose(data->file); 1516 | } 1517 | data->file = NULL; 1518 | data->fd = -1; 1519 | } else if (data->fd != -1) { 1520 | ret = close(data->fd); 1521 | data->fd = -1; 1522 | } else { 1523 | return 0;/* everything should be closed already -> success*/ 1524 | } 1525 | if (data->temp_file_name) { 1526 | unlink(data->temp_file_name); 1527 | /* temporary streams are never persistent */ 1528 | efree(data->temp_file_name); 1529 | } 1530 | } else { 1531 | ret = 0; 1532 | data->file = NULL; 1533 | } 1534 | pefree(data, stream->is_persistent); 1535 | 1536 | return ret; 1537 | } 1538 | 1539 | static int php_stdiop_flush(php_stream *stream TSRMLS_DC) 1540 | { 1541 | php_stdio_stream_data *data = (php_stdio_stream_data*)stream->abstract; 1542 | 1543 | assert(data != NULL); 1544 | 1545 | /* 1546 | * stdio buffers data in user land. By calling fflush(3), this 1547 | * data is send to the kernel using write(2). fsync'ing is 1548 | * something completely different. 1549 | */ 1550 | if (data->fd < 0) { 1551 | return fflush(data->file); 1552 | } 1553 | return 0; 1554 | } 1555 | 1556 | static int php_stdiop_seek(php_stream *stream, off_t offset, int whence, off_t *newoffset TSRMLS_DC) 1557 | { 1558 | php_stdio_stream_data *data = (php_stdio_stream_data*)stream->abstract; 1559 | int ret; 1560 | 1561 | assert(data != NULL); 1562 | 1563 | if (data->is_pipe) { 1564 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot seek on a pipe"); 1565 | return -1; 1566 | } 1567 | 1568 | if (data->fd >= 0) { 1569 | off_t result; 1570 | 1571 | result = lseek(data->fd, offset, whence); 1572 | if (result == (off_t)-1) 1573 | return -1; 1574 | 1575 | *newoffset = result; 1576 | return 0; 1577 | 1578 | } else { 1579 | ret = fseek(data->file, offset, whence); 1580 | *newoffset = ftell(data->file); 1581 | return ret; 1582 | } 1583 | } 1584 | 1585 | static int php_stdiop_cast(php_stream *stream, int castas, void **ret TSRMLS_DC) 1586 | { 1587 | int fd; 1588 | php_stdio_stream_data *data = (php_stdio_stream_data*) stream->abstract; 1589 | 1590 | assert(data != NULL); 1591 | 1592 | /* as soon as someone touches the stdio layer, buffering may ensue, 1593 | * so we need to stop using the fd directly in that case */ 1594 | 1595 | switch (castas) { 1596 | case PHP_STREAM_AS_STDIO: 1597 | if (ret) { 1598 | if (data->file == NULL) { 1599 | data->file = fdopen(data->fd, stream->mode); 1600 | if (data->file == NULL) { 1601 | return FAILURE; 1602 | } 1603 | } 1604 | *(FILE**)ret = data->file; 1605 | data->fd = -1; 1606 | } 1607 | return SUCCESS; 1608 | 1609 | case PHP_STREAM_AS_FD_FOR_SELECT: 1610 | PHP_STDIOP_GET_FD(fd, data); 1611 | if (fd < 0) { 1612 | return FAILURE; 1613 | } 1614 | if (ret) { 1615 | *(int*)ret = fd; 1616 | } 1617 | return SUCCESS; 1618 | 1619 | case PHP_STREAM_AS_FD: 1620 | PHP_STDIOP_GET_FD(fd, data); 1621 | 1622 | if (fd < 0) { 1623 | return FAILURE; 1624 | } 1625 | if (ret) { 1626 | if (data->file) { 1627 | fflush(data->file); 1628 | } 1629 | *(int*)ret = fd; 1630 | } 1631 | return SUCCESS; 1632 | default: 1633 | return FAILURE; 1634 | } 1635 | } 1636 | 1637 | static int php_stdiop_stat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC) 1638 | { 1639 | int fd; 1640 | php_stdio_stream_data *data = (php_stdio_stream_data*) stream->abstract; 1641 | 1642 | assert(data != NULL); 1643 | 1644 | PHP_STDIOP_GET_FD(fd, data); 1645 | 1646 | return fstat(fd, &ssb->sb); 1647 | } 1648 | 1649 | static int php_stdiop_set_option(php_stream *stream, int option, int value, void *ptrparam TSRMLS_DC) 1650 | { 1651 | php_stdio_stream_data *data = (php_stdio_stream_data*) stream->abstract; 1652 | size_t size; 1653 | int fd; 1654 | #ifdef O_NONBLOCK 1655 | /* FIXME: make this work for win32 */ 1656 | int flags; 1657 | int oldval; 1658 | #endif 1659 | 1660 | PHP_STDIOP_GET_FD(fd, data); 1661 | 1662 | switch(option) { 1663 | case PHP_STREAM_OPTION_BLOCKING: 1664 | if (fd == -1) 1665 | return -1; 1666 | #ifdef O_NONBLOCK 1667 | flags = fcntl(fd, F_GETFL, 0); 1668 | oldval = (flags & O_NONBLOCK) ? 0 : 1; 1669 | if (value) 1670 | flags &= ~O_NONBLOCK; 1671 | else 1672 | flags |= O_NONBLOCK; 1673 | 1674 | if (-1 == fcntl(fd, F_SETFL, flags)) 1675 | return -1; 1676 | return oldval; 1677 | #else 1678 | return -1; /* not yet implemented */ 1679 | #endif 1680 | 1681 | case PHP_STREAM_OPTION_WRITE_BUFFER: 1682 | if (data->file == NULL) { 1683 | return -1; 1684 | } 1685 | 1686 | if (ptrparam) 1687 | size = *(size_t *)ptrparam; 1688 | else 1689 | size = BUFSIZ; 1690 | 1691 | switch(value) { 1692 | case PHP_STREAM_BUFFER_NONE: 1693 | stream->flags |= PHP_STREAM_FLAG_NO_BUFFER; 1694 | return setvbuf(data->file, NULL, _IONBF, 0); 1695 | 1696 | case PHP_STREAM_BUFFER_LINE: 1697 | stream->flags ^= PHP_STREAM_FLAG_NO_BUFFER; 1698 | return setvbuf(data->file, NULL, _IOLBF, size); 1699 | 1700 | case PHP_STREAM_BUFFER_FULL: 1701 | stream->flags ^= PHP_STREAM_FLAG_NO_BUFFER; 1702 | return setvbuf(data->file, NULL, _IOFBF, size); 1703 | 1704 | default: 1705 | return -1; 1706 | } 1707 | break; 1708 | default: 1709 | return -1; 1710 | } 1711 | } 1712 | 1713 | PHPAPI php_stream_ops php_stream_stdio_ops = { 1714 | php_stdiop_write, php_stdiop_read, 1715 | php_stdiop_close, php_stdiop_flush, 1716 | "STDIO", 1717 | php_stdiop_seek, 1718 | php_stdiop_cast, 1719 | php_stdiop_stat, 1720 | php_stdiop_set_option 1721 | }; 1722 | /* }}} */ 1723 | 1724 | /* {{{ php_stream_fopen_with_path */ 1725 | PHPAPI php_stream *_php_stream_fopen_with_path(char *filename, char *mode, char *path, char **opened_path, int options STREAMS_DC TSRMLS_DC) 1726 | { 1727 | /* code ripped off from fopen_wrappers.c */ 1728 | char *pathbuf, *ptr, *end; 1729 | char *exec_fname; 1730 | char trypath[MAXPATHLEN]; 1731 | struct stat sb; 1732 | php_stream *stream; 1733 | int path_length; 1734 | int filename_length; 1735 | int exec_fname_length; 1736 | 1737 | if (opened_path) { 1738 | *opened_path = NULL; 1739 | } 1740 | 1741 | if (!filename) { 1742 | return NULL; 1743 | } 1744 | 1745 | filename_length = strlen(filename); 1746 | 1747 | /* Relative path open */ 1748 | if (*filename == '.' && (IS_SLASH(filename[1]) || filename[1] == '.')) { 1749 | /* further checks, we could have ....... filenames */ 1750 | ptr = filename + 1; 1751 | if (*ptr == '.') { 1752 | while (*(++ptr) == '.'); 1753 | if (!IS_SLASH(*ptr)) { /* not a relative path after all */ 1754 | goto not_relative_path; 1755 | } 1756 | } 1757 | 1758 | if (php_check_open_basedir(filename TSRMLS_CC)) { 1759 | return NULL; 1760 | } 1761 | 1762 | if (PG(safe_mode) && (!php_checkuid(filename, mode, CHECKUID_CHECK_MODE_PARAM))) { 1763 | return NULL; 1764 | } 1765 | return php_stream_fopen_rel(filename, mode, opened_path, options); 1766 | } 1767 | 1768 | /* 1769 | * files in safe_mode_include_dir (or subdir) are excluded from 1770 | * safe mode GID/UID checks 1771 | */ 1772 | 1773 | not_relative_path: 1774 | 1775 | /* Absolute path open */ 1776 | if (IS_ABSOLUTE_PATH(filename, filename_length)) { 1777 | 1778 | if (php_check_open_basedir(filename TSRMLS_CC)) { 1779 | return NULL; 1780 | } 1781 | 1782 | if ((php_check_safe_mode_include_dir(filename TSRMLS_CC)) == 0) 1783 | /* filename is in safe_mode_include_dir (or subdir) */ 1784 | return php_stream_fopen_rel(filename, mode, opened_path, options); 1785 | 1786 | if (PG(safe_mode) && (!php_checkuid(filename, mode, CHECKUID_CHECK_MODE_PARAM))) 1787 | return NULL; 1788 | 1789 | return php_stream_fopen_rel(filename, mode, opened_path, options); 1790 | } 1791 | 1792 | #ifdef PHP_WIN32 1793 | if (IS_SLASH(filename[0])) { 1794 | int cwd_len; 1795 | char *cwd; 1796 | cwd = virtual_getcwd_ex(&cwd_len TSRMLS_CC); 1797 | /* getcwd() will return always return [DRIVE_LETTER]:/) on windows. */ 1798 | *(cwd+3) = '\0'; 1799 | 1800 | snprintf(trypath, MAXPATHLEN, "%s%s", cwd, filename); 1801 | 1802 | free(cwd); 1803 | 1804 | if (php_check_open_basedir(trypath TSRMLS_CC)) { 1805 | return NULL; 1806 | } 1807 | if ((php_check_safe_mode_include_dir(trypath TSRMLS_CC)) == 0) { 1808 | return php_stream_fopen_rel(trypath, mode, opened_path, options); 1809 | } 1810 | if (PG(safe_mode) && (!php_checkuid(trypath, mode, CHECKUID_CHECK_MODE_PARAM))) { 1811 | return NULL; 1812 | } 1813 | 1814 | return php_stream_fopen_rel(trypath, mode, opened_path, options); 1815 | } 1816 | #endif 1817 | 1818 | if (!path || (path && !*path)) { 1819 | 1820 | if (php_check_open_basedir(path TSRMLS_CC)) { 1821 | return NULL; 1822 | } 1823 | 1824 | if (PG(safe_mode) && (!php_checkuid(filename, mode, CHECKUID_CHECK_MODE_PARAM))) { 1825 | return NULL; 1826 | } 1827 | return php_stream_fopen_rel(filename, mode, opened_path, options); 1828 | } 1829 | 1830 | /* check in provided path */ 1831 | /* append the calling scripts' current working directory 1832 | * as a fall back case 1833 | */ 1834 | if (zend_is_executing(TSRMLS_C)) { 1835 | exec_fname = zend_get_executed_filename(TSRMLS_C); 1836 | exec_fname_length = strlen(exec_fname); 1837 | path_length = strlen(path); 1838 | 1839 | while ((--exec_fname_length >= 0) && !IS_SLASH(exec_fname[exec_fname_length])); 1840 | if ((exec_fname && exec_fname[0] == '[') 1841 | || exec_fname_length<=0) { 1842 | /* [no active file] or no path */ 1843 | pathbuf = estrdup(path); 1844 | } else { 1845 | pathbuf = (char *) emalloc(exec_fname_length + path_length +1 +1); 1846 | memcpy(pathbuf, path, path_length); 1847 | pathbuf[path_length] = DEFAULT_DIR_SEPARATOR; 1848 | memcpy(pathbuf+path_length+1, exec_fname, exec_fname_length); 1849 | pathbuf[path_length + exec_fname_length +1] = '\0'; 1850 | } 1851 | } else { 1852 | pathbuf = estrdup(path); 1853 | } 1854 | 1855 | ptr = pathbuf; 1856 | 1857 | while (ptr && *ptr) { 1858 | end = strchr(ptr, DEFAULT_DIR_SEPARATOR); 1859 | if (end != NULL) { 1860 | *end = '\0'; 1861 | end++; 1862 | } 1863 | snprintf(trypath, MAXPATHLEN, "%s/%s", ptr, filename); 1864 | 1865 | /* If file does not exist continue */ 1866 | if (VCWD_STAT(trypath, &sb) != 0) { 1867 | ptr = end; 1868 | continue; 1869 | } 1870 | 1871 | if (php_check_open_basedir(trypath TSRMLS_CC)) { 1872 | stream = NULL; 1873 | goto stream_done; 1874 | } 1875 | 1876 | if (PG(safe_mode)) { 1877 | /* file exists ... check permission */ 1878 | if ((php_check_safe_mode_include_dir(trypath TSRMLS_CC) == 0) || 1879 | php_checkuid(trypath, mode, CHECKUID_CHECK_MODE_PARAM)) { 1880 | /* UID ok, or trypath is in safe_mode_include_dir */ 1881 | stream = php_stream_fopen_rel(trypath, mode, opened_path, options); 1882 | } else { 1883 | stream = NULL; 1884 | } 1885 | goto stream_done; 1886 | } 1887 | stream = php_stream_fopen_rel(trypath, mode, opened_path, options); 1888 | if (stream) { 1889 | stream_done: 1890 | efree(pathbuf); 1891 | return stream; 1892 | } 1893 | ptr = end; 1894 | } /* end provided path */ 1895 | 1896 | efree(pathbuf); 1897 | return NULL; 1898 | 1899 | } 1900 | /* }}} */ 1901 | 1902 | #ifndef S_ISREG 1903 | #define S_ISREG(mode) (((mode)&S_IFMT) == S_IFREG) 1904 | #endif 1905 | 1906 | /* parse standard "fopen" modes into open() flags */ 1907 | PHPAPI int php_stream_parse_fopen_modes(const char *mode, int *open_flags) 1908 | { 1909 | int flags; 1910 | 1911 | switch (mode[0]) { 1912 | case 'r': 1913 | flags = 0; 1914 | break; 1915 | case 'w': 1916 | flags = O_TRUNC|O_CREAT; 1917 | break; 1918 | case 'a': 1919 | flags = O_CREAT|O_APPEND; 1920 | break; 1921 | case 'x': 1922 | flags = O_CREAT|O_EXCL; 1923 | break; 1924 | default: 1925 | /* unknown mode */ 1926 | return FAILURE; 1927 | } 1928 | 1929 | if (strchr(mode, '+')) { 1930 | flags |= O_RDWR; 1931 | } else if (flags) { 1932 | flags |= O_WRONLY; 1933 | } else { 1934 | flags |= O_RDONLY; 1935 | } 1936 | 1937 | #if defined(_O_TEXT) && defined(O_BINARY) 1938 | if (strchr(mode, 't')) { 1939 | flags |= _O_TEXT; 1940 | } else { 1941 | flags |= O_BINARY; 1942 | } 1943 | #endif 1944 | 1945 | *open_flags = flags; 1946 | return SUCCESS; 1947 | } 1948 | 1949 | 1950 | /* {{{ php_stream_fopen */ 1951 | PHPAPI php_stream *_php_stream_fopen(const char *filename, const char *mode, char **opened_path, int options STREAMS_DC TSRMLS_DC) 1952 | { 1953 | char *realpath = NULL; 1954 | struct stat st; 1955 | int open_flags; 1956 | int fd; 1957 | php_stream *ret = NULL; 1958 | int persistent = options & STREAM_OPEN_PERSISTENT; 1959 | char *persistent_id = NULL; 1960 | 1961 | if (FAILURE == php_stream_parse_fopen_modes(mode, &open_flags)) { 1962 | if (options & REPORT_ERRORS) { 1963 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "`%s' is not a valid mode for fopen", mode); 1964 | } 1965 | return NULL; 1966 | } 1967 | 1968 | if ((realpath = expand_filepath(filename, NULL TSRMLS_CC)) == NULL) { 1969 | return NULL; 1970 | } 1971 | 1972 | if (persistent) { 1973 | spprintf(&persistent_id, 0, "streams_stdio_%d_%s", open_flags, realpath); 1974 | switch (php_stream_from_persistent_id(persistent_id, &ret TSRMLS_CC)) { 1975 | case PHP_STREAM_PERSISTENT_SUCCESS: 1976 | if (opened_path) { 1977 | *opened_path = realpath; 1978 | realpath = NULL; 1979 | } 1980 | if (realpath) { 1981 | efree(realpath); 1982 | } 1983 | /* fall through */ 1984 | 1985 | case PHP_STREAM_PERSISTENT_FAILURE: 1986 | efree(persistent_id);; 1987 | return ret; 1988 | } 1989 | } 1990 | 1991 | fd = open(realpath, open_flags, 0666); 1992 | 1993 | if (fd != -1) { 1994 | /* sanity checks for include/require */ 1995 | if (options & STREAM_OPEN_FOR_INCLUDE && (fstat(fd, &st) == -1 || !S_ISREG(st.st_mode))) { 1996 | #ifdef PHP_WIN32 1997 | /* skip the sanity check; fstat doesn't appear to work on 1998 | * UNC paths */ 1999 | if (!IS_UNC_PATH(filename, strlen(filename))) 2000 | #endif 2001 | goto err; 2002 | } 2003 | 2004 | ret = php_stream_fopen_from_fd_rel(fd, mode, persistent_id); 2005 | 2006 | if (ret) { 2007 | if (opened_path) { 2008 | *opened_path = realpath; 2009 | realpath = NULL; 2010 | } 2011 | if (realpath) { 2012 | efree(realpath); 2013 | } 2014 | if (persistent_id) { 2015 | efree(persistent_id); 2016 | } 2017 | 2018 | return ret; 2019 | } 2020 | err: 2021 | close(fd); 2022 | } 2023 | efree(realpath); 2024 | if (persistent_id) { 2025 | efree(persistent_id); 2026 | } 2027 | return NULL; 2028 | } 2029 | /* }}} */ 2030 | 2031 | PHPAPI php_stream *_php_stream_fopen_from_fd(int fd, const char *mode, const char *persistent_id STREAMS_DC TSRMLS_DC) 2032 | { 2033 | php_stdio_stream_data *self; 2034 | php_stream *stream; 2035 | #if defined(S_ISFIFO) || defined(S_ISSOCK) 2036 | struct stat sb; 2037 | int stat_ok; 2038 | 2039 | stat_ok = fd >= 0 && fstat(fd, &sb) == 0; 2040 | #endif 2041 | 2042 | #if defined(S_ISSOCK) 2043 | if (stat_ok && S_ISSOCK(sb.st_mode)) { 2044 | return _php_stream_sock_open_from_socket(fd, persistent_id STREAMS_CC TSRMLS_CC); 2045 | } 2046 | #endif 2047 | 2048 | self = pemalloc_rel_orig(sizeof(*self), persistent_id); 2049 | memset(self, 0, sizeof(*self)); 2050 | self->file = NULL; 2051 | self->is_pipe = 0; 2052 | self->is_process_pipe = 0; 2053 | self->temp_file_name = NULL; 2054 | self->fd = fd; 2055 | 2056 | #ifdef S_ISFIFO 2057 | /* detect if this is a pipe */ 2058 | if (stat_ok) { 2059 | self->is_pipe = S_ISFIFO(sb.st_mode) ? 1 : 0; 2060 | } 2061 | #elif defined(PHP_WIN32) 2062 | { 2063 | long handle = _get_osfhandle(self->fd); 2064 | DWORD in_buf_size, out_buf_size; 2065 | 2066 | if (handle != 0xFFFFFFFF) { 2067 | self->is_pipe = GetNamedPipeInfo((HANDLE)handle, NULL, &out_buf_size, &in_buf_size, NULL); 2068 | } 2069 | } 2070 | #endif 2071 | 2072 | stream = php_stream_alloc_rel(&php_stream_stdio_ops, self, persistent_id, mode); 2073 | 2074 | if (stream) { 2075 | if (self->is_pipe) { 2076 | stream->flags |= PHP_STREAM_FLAG_NO_SEEK | PHP_STREAM_FLAG_AVOID_BLOCKING; 2077 | } else { 2078 | stream->position = lseek(self->fd, 0, SEEK_CUR); 2079 | } 2080 | } 2081 | 2082 | return stream; 2083 | } 2084 | 2085 | 2086 | /* {{{ STDIO with fopencookie */ 2087 | #if HAVE_FUNOPEN 2088 | /* use our fopencookie emulation */ 2089 | static int stream_cookie_reader(void *cookie, char *buffer, int size) 2090 | { 2091 | int ret; 2092 | TSRMLS_FETCH(); 2093 | ret = php_stream_read((php_stream*)cookie, buffer, size); 2094 | return ret; 2095 | } 2096 | 2097 | static int stream_cookie_writer(void *cookie, const char *buffer, int size) 2098 | { 2099 | TSRMLS_FETCH(); 2100 | return php_stream_write((php_stream *)cookie, (char *)buffer, size); 2101 | } 2102 | 2103 | static fpos_t stream_cookie_seeker(void *cookie, off_t position, int whence) 2104 | { 2105 | TSRMLS_FETCH(); 2106 | return (fpos_t)php_stream_seek((php_stream *)cookie, position, whence); 2107 | } 2108 | 2109 | static int stream_cookie_closer(void *cookie) 2110 | { 2111 | php_stream *stream = (php_stream*)cookie; 2112 | TSRMLS_FETCH(); 2113 | 2114 | /* prevent recursion */ 2115 | stream->fclose_stdiocast = PHP_STREAM_FCLOSE_NONE; 2116 | return php_stream_close(stream); 2117 | } 2118 | 2119 | #elif HAVE_FOPENCOOKIE 2120 | static ssize_t stream_cookie_reader(void *cookie, char *buffer, size_t size) 2121 | { 2122 | ssize_t ret; 2123 | TSRMLS_FETCH(); 2124 | ret = php_stream_read(((php_stream *)cookie), buffer, size); 2125 | return ret; 2126 | } 2127 | 2128 | static ssize_t stream_cookie_writer(void *cookie, const char *buffer, size_t size) 2129 | { 2130 | TSRMLS_FETCH(); 2131 | return php_stream_write(((php_stream *)cookie), (char *)buffer, size); 2132 | } 2133 | 2134 | #ifdef COOKIE_SEEKER_USES_OFF64_T 2135 | static int stream_cookie_seeker(void *cookie, __off64_t *position, int whence) 2136 | { 2137 | TSRMLS_FETCH(); 2138 | 2139 | *position = php_stream_seek((php_stream *)cookie, (off_t)*position, whence); 2140 | 2141 | if (*position == -1) 2142 | return -1; 2143 | return 0; 2144 | } 2145 | #else 2146 | static int stream_cookie_seeker(void *cookie, off_t position, int whence) 2147 | { 2148 | TSRMLS_FETCH(); 2149 | return php_stream_seek((php_stream *)cookie, position, whence); 2150 | } 2151 | #endif 2152 | 2153 | static int stream_cookie_closer(void *cookie) 2154 | { 2155 | php_stream *stream = (php_stream*)cookie; 2156 | TSRMLS_FETCH(); 2157 | 2158 | /* prevent recursion */ 2159 | stream->fclose_stdiocast = PHP_STREAM_FCLOSE_NONE; 2160 | return php_stream_close(stream); 2161 | } 2162 | #endif /* elif HAVE_FOPENCOOKIE */ 2163 | 2164 | #if HAVE_FOPENCOOKIE 2165 | static COOKIE_IO_FUNCTIONS_T stream_cookie_functions = 2166 | { 2167 | stream_cookie_reader, stream_cookie_writer, 2168 | stream_cookie_seeker, stream_cookie_closer 2169 | }; 2170 | #else 2171 | /* TODO: use socketpair() to emulate fopencookie, as suggested by Hartmut ? */ 2172 | #endif 2173 | /* }}} */ 2174 | 2175 | /* {{{ php_stream_cast */ 2176 | PHPAPI int _php_stream_cast(php_stream *stream, int castas, void **ret, int show_err TSRMLS_DC) 2177 | { 2178 | int flags = castas & PHP_STREAM_CAST_MASK; 2179 | castas &= ~PHP_STREAM_CAST_MASK; 2180 | 2181 | /* synchronize our buffer (if possible) */ 2182 | if (ret && castas != PHP_STREAM_AS_FD_FOR_SELECT) { 2183 | php_stream_flush(stream); 2184 | if (stream->ops->seek && (stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0) { 2185 | off_t dummy; 2186 | 2187 | stream->ops->seek(stream, stream->position, SEEK_SET, &dummy TSRMLS_CC); 2188 | stream->readpos = stream->writepos = 0; 2189 | } 2190 | } 2191 | 2192 | /* filtered streams can only be cast as stdio, and only when fopencookie is present */ 2193 | 2194 | if (castas == PHP_STREAM_AS_STDIO) { 2195 | if (stream->stdiocast) { 2196 | if (ret) { 2197 | *(FILE**)ret = stream->stdiocast; 2198 | } 2199 | goto exit_success; 2200 | } 2201 | 2202 | /* if the stream is a stdio stream let's give it a chance to respond 2203 | * first, to avoid doubling up the layers of stdio with an fopencookie */ 2204 | if (php_stream_is(stream, PHP_STREAM_IS_STDIO) && 2205 | stream->ops->cast && 2206 | stream->filterhead == NULL && 2207 | stream->ops->cast(stream, castas, ret TSRMLS_CC) == SUCCESS) 2208 | { 2209 | goto exit_success; 2210 | } 2211 | 2212 | #if HAVE_FOPENCOOKIE 2213 | /* if just checking, say yes we can be a FILE*, but don't actually create it yet */ 2214 | if (ret == NULL) 2215 | goto exit_success; 2216 | 2217 | *(FILE**)ret = fopencookie(stream, stream->mode, PHP_STREAM_COOKIE_FUNCTIONS); 2218 | 2219 | if (*ret != NULL) { 2220 | off_t pos; 2221 | 2222 | stream->fclose_stdiocast = PHP_STREAM_FCLOSE_FOPENCOOKIE; 2223 | 2224 | /* If the stream position is not at the start, we need to force 2225 | * the stdio layer to believe it's real location. */ 2226 | pos = php_stream_tell(stream); 2227 | if (pos > 0) 2228 | fseek(*ret, pos, SEEK_SET); 2229 | 2230 | goto exit_success; 2231 | } 2232 | 2233 | /* must be either: 2234 | a) programmer error 2235 | b) no memory 2236 | -> lets bail 2237 | */ 2238 | php_error_docref(NULL TSRMLS_CC, E_ERROR, "fopencookie failed"); 2239 | return FAILURE; 2240 | #endif 2241 | 2242 | if (!stream->filterhead && stream->ops->cast && stream->ops->cast(stream, castas, NULL TSRMLS_CC) == SUCCESS) { 2243 | if (FAILURE == stream->ops->cast(stream, castas, ret TSRMLS_CC)) { 2244 | return FAILURE; 2245 | } 2246 | goto exit_success; 2247 | } else if (flags & PHP_STREAM_CAST_TRY_HARD) { 2248 | php_stream *newstream; 2249 | 2250 | newstream = php_stream_fopen_tmpfile(); 2251 | if (newstream) { 2252 | size_t copied = php_stream_copy_to_stream(stream, newstream, PHP_STREAM_COPY_ALL); 2253 | 2254 | if (copied == 0) { 2255 | php_stream_close(newstream); 2256 | } else { 2257 | int retcode = php_stream_cast(newstream, castas | flags, ret, show_err); 2258 | 2259 | if (retcode == SUCCESS) 2260 | rewind(*(FILE**)ret); 2261 | 2262 | /* do some specialized cleanup */ 2263 | if ((flags & PHP_STREAM_CAST_RELEASE)) { 2264 | php_stream_free(stream, PHP_STREAM_FREE_CLOSE_CASTED); 2265 | } 2266 | 2267 | return retcode; 2268 | } 2269 | } 2270 | } 2271 | } 2272 | 2273 | if (stream->filterhead) { 2274 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot cast a filtered stream on this system"); 2275 | return FAILURE; 2276 | } else if (stream->ops->cast && stream->ops->cast(stream, castas, ret TSRMLS_CC) == SUCCESS) { 2277 | goto exit_success; 2278 | } 2279 | 2280 | if (show_err) { 2281 | /* these names depend on the values of the PHP_STREAM_AS_XXX defines in php_streams.h */ 2282 | static const char *cast_names[4] = { 2283 | "STDIO FILE*", "File Descriptor", "Socket Descriptor", "select()able descriptor" 2284 | }; 2285 | 2286 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot represent a stream of type %s as a %s", 2287 | stream->ops->label, 2288 | cast_names[castas] 2289 | ); 2290 | } 2291 | 2292 | return FAILURE; 2293 | 2294 | exit_success: 2295 | 2296 | if ((stream->writepos - stream->readpos) > 0 && 2297 | stream->fclose_stdiocast != PHP_STREAM_FCLOSE_FOPENCOOKIE && 2298 | (flags & PHP_STREAM_CAST_INTERNAL) == 0) { 2299 | /* the data we have buffered will be lost to the third party library that 2300 | * will be accessing the stream. Emit a warning so that the end-user will 2301 | * know that they should try something else */ 2302 | 2303 | php_error_docref(NULL TSRMLS_CC, E_WARNING, 2304 | "%ld bytes of buffered data lost during conversion to FILE*!", 2305 | stream->writepos - stream->readpos); 2306 | } 2307 | 2308 | if (castas == PHP_STREAM_AS_STDIO && ret) 2309 | stream->stdiocast = *(FILE**)ret; 2310 | 2311 | if (flags & PHP_STREAM_CAST_RELEASE) { 2312 | php_stream_free(stream, PHP_STREAM_FREE_CLOSE_CASTED); 2313 | } 2314 | 2315 | return SUCCESS; 2316 | 2317 | } 2318 | /* }}} */ 2319 | 2320 | /* {{{ wrapper init and registration */ 2321 | 2322 | static void stream_resource_regular_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC) 2323 | { 2324 | php_stream *stream = (php_stream*)rsrc->ptr; 2325 | /* set the return value for pclose */ 2326 | FG(pclose_ret) = php_stream_free(stream, PHP_STREAM_FREE_CLOSE | PHP_STREAM_FREE_RSRC_DTOR); 2327 | } 2328 | 2329 | static void stream_resource_persistent_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC) 2330 | { 2331 | php_stream *stream = (php_stream*)rsrc->ptr; 2332 | FG(pclose_ret) = php_stream_free(stream, PHP_STREAM_FREE_CLOSE | PHP_STREAM_FREE_RSRC_DTOR); 2333 | } 2334 | 2335 | void php_shutdown_stream_hashes(TSRMLS_D) 2336 | { 2337 | if (FG(stream_wrappers)) { 2338 | zend_hash_destroy(FG(stream_wrappers)); 2339 | efree(FG(stream_wrappers)); 2340 | FG(stream_wrappers) = NULL; 2341 | } 2342 | } 2343 | 2344 | int php_init_stream_wrappers(int module_number TSRMLS_DC) 2345 | { 2346 | le_stream = zend_register_list_destructors_ex(stream_resource_regular_dtor, NULL, "stream", module_number); 2347 | le_pstream = zend_register_list_destructors_ex(NULL, stream_resource_persistent_dtor, "persistent stream", module_number); 2348 | 2349 | return ( 2350 | zend_hash_init(&url_stream_wrappers_hash, 0, NULL, NULL, 1) == SUCCESS 2351 | && 2352 | zend_hash_init(&stream_filters_hash, 0, NULL, NULL, 1) == SUCCESS 2353 | ) ? SUCCESS : FAILURE; 2354 | } 2355 | 2356 | int php_shutdown_stream_wrappers(int module_number TSRMLS_DC) 2357 | { 2358 | zend_hash_destroy(&url_stream_wrappers_hash); 2359 | zend_hash_destroy(&stream_filters_hash); 2360 | return SUCCESS; 2361 | } 2362 | 2363 | /* API for registering GLOBAL wrappers */ 2364 | PHPAPI int php_register_url_stream_wrapper(char *protocol, php_stream_wrapper *wrapper TSRMLS_DC) 2365 | { 2366 | int i, protocol_len = strlen(protocol); 2367 | 2368 | for(i = 0; i < protocol_len; i++) { 2369 | if (!isalnum((int)protocol[i]) && 2370 | protocol[i] != '+' && 2371 | protocol[i] != '-' && 2372 | protocol[i] != '.') { 2373 | return FAILURE; 2374 | } 2375 | } 2376 | 2377 | return zend_hash_add(&url_stream_wrappers_hash, protocol, protocol_len, wrapper, sizeof(*wrapper), NULL); 2378 | } 2379 | 2380 | PHPAPI int php_unregister_url_stream_wrapper(char *protocol TSRMLS_DC) 2381 | { 2382 | return zend_hash_del(&url_stream_wrappers_hash, protocol, strlen(protocol)); 2383 | } 2384 | 2385 | /* API for registering VOLATILE wrappers */ 2386 | PHPAPI int php_register_url_stream_wrapper_volatile(char *protocol, php_stream_wrapper *wrapper TSRMLS_DC) 2387 | { 2388 | int i, protocol_len = strlen(protocol); 2389 | 2390 | for(i = 0; i < protocol_len; i++) { 2391 | if (!isalnum((int)protocol[i]) && 2392 | protocol[i] != '+' && 2393 | protocol[i] != '-' && 2394 | protocol[i] != '.') { 2395 | return FAILURE; 2396 | } 2397 | } 2398 | 2399 | if (!FG(stream_wrappers)) { 2400 | php_stream_wrapper tmpwrapper; 2401 | 2402 | FG(stream_wrappers) = emalloc(sizeof(HashTable)); 2403 | zend_hash_init(FG(stream_wrappers), 0, NULL, NULL, 1); 2404 | zend_hash_copy(FG(stream_wrappers), &url_stream_wrappers_hash, NULL, &tmpwrapper, sizeof(php_stream_wrapper)); 2405 | } 2406 | 2407 | return zend_hash_add(FG(stream_wrappers), protocol, protocol_len, wrapper, sizeof(*wrapper), NULL); 2408 | } 2409 | /* }}} */ 2410 | 2411 | 2412 | static size_t php_plain_files_dirstream_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) 2413 | { 2414 | DIR *dir = (DIR*)stream->abstract; 2415 | /* avoid libc5 readdir problems */ 2416 | char entry[sizeof(struct dirent)+MAXPATHLEN]; 2417 | struct dirent *result = (struct dirent *)&entry; 2418 | php_stream_dirent *ent = (php_stream_dirent*)buf; 2419 | 2420 | /* avoid problems if someone mis-uses the stream */ 2421 | if (count != sizeof(php_stream_dirent)) 2422 | return 0; 2423 | 2424 | if (php_readdir_r(dir, (struct dirent *)entry, &result) == 0 && result) { 2425 | PHP_STRLCPY(ent->d_name, result->d_name, sizeof(ent->d_name), strlen(result->d_name)); 2426 | return sizeof(php_stream_dirent); 2427 | } 2428 | return 0; 2429 | } 2430 | 2431 | static int php_plain_files_dirstream_close(php_stream *stream, int close_handle TSRMLS_DC) 2432 | { 2433 | return closedir((DIR *)stream->abstract); 2434 | } 2435 | 2436 | static int php_plain_files_dirstream_rewind(php_stream *stream, off_t offset, int whence, off_t *newoffs TSRMLS_DC) 2437 | { 2438 | rewinddir((DIR *)stream->abstract); 2439 | return 0; 2440 | } 2441 | 2442 | static php_stream_ops php_plain_files_dirstream_ops = { 2443 | NULL, php_plain_files_dirstream_read, 2444 | php_plain_files_dirstream_close, NULL, 2445 | "dir", 2446 | php_plain_files_dirstream_rewind, 2447 | NULL, /* cast */ 2448 | NULL, /* stat */ 2449 | NULL /* set_option */ 2450 | }; 2451 | 2452 | static php_stream *php_plain_files_dir_opener(php_stream_wrapper *wrapper, char *path, char *mode, 2453 | int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC) 2454 | { 2455 | DIR *dir = NULL; 2456 | php_stream *stream = NULL; 2457 | 2458 | if (php_check_open_basedir(path TSRMLS_CC)) { 2459 | return NULL; 2460 | } 2461 | 2462 | if (PG(safe_mode) &&(!php_checkuid(path, NULL, CHECKUID_CHECK_FILE_AND_DIR))) { 2463 | return NULL; 2464 | } 2465 | 2466 | dir = VCWD_OPENDIR(path); 2467 | 2468 | #ifdef PHP_WIN32 2469 | if (dir && dir->finished) { 2470 | closedir(dir); 2471 | dir = NULL; 2472 | } 2473 | #endif 2474 | if (dir) { 2475 | stream = php_stream_alloc(&php_plain_files_dirstream_ops, dir, 0, mode); 2476 | if (stream == NULL) 2477 | closedir(dir); 2478 | } 2479 | 2480 | return stream; 2481 | } 2482 | 2483 | 2484 | 2485 | static php_stream *php_plain_files_stream_opener(php_stream_wrapper *wrapper, char *path, char *mode, 2486 | int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC) 2487 | { 2488 | if ((options & USE_PATH) && PG(include_path) != NULL) { 2489 | return php_stream_fopen_with_path_rel(path, mode, PG(include_path), opened_path, options); 2490 | } 2491 | 2492 | if (((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) && php_check_open_basedir(path TSRMLS_CC)) { 2493 | return NULL; 2494 | } 2495 | 2496 | if ((options & ENFORCE_SAFE_MODE) && PG(safe_mode) && (!php_checkuid(path, mode, CHECKUID_CHECK_MODE_PARAM))) 2497 | return NULL; 2498 | 2499 | return php_stream_fopen_rel(path, mode, opened_path, options); 2500 | } 2501 | 2502 | static int php_plain_files_url_stater(php_stream_wrapper *wrapper, char *url, php_stream_statbuf *ssb TSRMLS_DC) 2503 | { 2504 | return VCWD_STAT(url, &ssb->sb); 2505 | } 2506 | 2507 | static php_stream_wrapper_ops php_plain_files_wrapper_ops = { 2508 | php_plain_files_stream_opener, 2509 | NULL, 2510 | NULL, 2511 | php_plain_files_url_stater, 2512 | php_plain_files_dir_opener, 2513 | "plainfile" 2514 | }; 2515 | 2516 | static php_stream_wrapper php_plain_files_wrapper = { 2517 | &php_plain_files_wrapper_ops, 2518 | NULL, 2519 | 0 2520 | }; 2521 | 2522 | PHPAPI php_stream_wrapper *php_stream_locate_url_wrapper(const char *path, char **path_for_open, int options TSRMLS_DC) 2523 | { 2524 | HashTable *wrapper_hash = (FG(stream_wrappers) ? FG(stream_wrappers) : &url_stream_wrappers_hash); 2525 | php_stream_wrapper *wrapper = NULL; 2526 | const char *p, *protocol = NULL; 2527 | int n = 0; 2528 | 2529 | if (path_for_open) 2530 | *path_for_open = (char*)path; 2531 | 2532 | if (options & IGNORE_URL) 2533 | return (options & STREAM_LOCATE_WRAPPERS_ONLY) ? NULL : &php_plain_files_wrapper; 2534 | 2535 | for (p = path; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; p++) { 2536 | n++; 2537 | } 2538 | 2539 | if ((*p == ':') && (n > 1) && !strncmp("://", p, 3)) { 2540 | protocol = path; 2541 | } else if (strncasecmp(path, "zlib:", 5) == 0) { 2542 | /* BC with older php scripts and zlib wrapper */ 2543 | protocol = "compress.zlib"; 2544 | n = 13; 2545 | if (options & REPORT_ERRORS) { 2546 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "Use of \"zlib:\" wrapper is deprecated; please use \"compress.zlib://\" instead."); 2547 | } 2548 | } 2549 | 2550 | if (protocol) { 2551 | if (FAILURE == zend_hash_find(wrapper_hash, (char*)protocol, n, (void**)&wrapper)) { 2552 | char wrapper_name[32]; 2553 | 2554 | if (options & REPORT_ERRORS) { 2555 | if (n >= sizeof(wrapper_name)) 2556 | n = sizeof(wrapper_name) - 1; 2557 | PHP_STRLCPY(wrapper_name, protocol, sizeof(wrapper_name), n); 2558 | 2559 | php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unable to find the wrapper \"%s\" - did you forget to enable it when you configured PHP?", 2560 | wrapper_name); 2561 | } 2562 | 2563 | wrapper = NULL; 2564 | protocol = NULL; 2565 | } 2566 | } 2567 | /* TODO: curl based streams probably support file:// properly */ 2568 | if (!protocol || !strncasecmp(protocol, "file", n)) { 2569 | if (protocol && path[n+1] == '/' && path[n+2] == '/') { 2570 | if (options & REPORT_ERRORS) 2571 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "remote host file access not supported, %s", path); 2572 | return NULL; 2573 | } 2574 | if (protocol && path_for_open) 2575 | *path_for_open = (char*)path + n + 1; 2576 | 2577 | /* fall back on regular file access */ 2578 | return (options & STREAM_LOCATE_WRAPPERS_ONLY) ? NULL : &php_plain_files_wrapper; 2579 | } 2580 | 2581 | if (wrapper && wrapper->is_url && !PG(allow_url_fopen)) { 2582 | if (options & REPORT_ERRORS) 2583 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "URL file-access is disabled in the server configuration"); 2584 | return NULL; 2585 | } 2586 | 2587 | return wrapper; 2588 | } 2589 | 2590 | PHPAPI int _php_stream_stat_path(char *path, php_stream_statbuf *ssb TSRMLS_DC) 2591 | { 2592 | php_stream_wrapper *wrapper = NULL; 2593 | char *path_to_open = path; 2594 | 2595 | wrapper = php_stream_locate_url_wrapper(path, &path_to_open, ENFORCE_SAFE_MODE TSRMLS_CC); 2596 | if (wrapper && wrapper->wops->url_stat) { 2597 | return wrapper->wops->url_stat(wrapper, path_to_open, ssb TSRMLS_CC); 2598 | } 2599 | return -1; 2600 | } 2601 | 2602 | /* {{{ php_stream_opendir */ 2603 | PHPAPI php_stream *_php_stream_opendir(char *path, int options, 2604 | php_stream_context *context STREAMS_DC TSRMLS_DC) 2605 | { 2606 | php_stream *stream = NULL; 2607 | php_stream_wrapper *wrapper = NULL; 2608 | char *path_to_open; 2609 | 2610 | if (!path || !*path) 2611 | return NULL; 2612 | 2613 | path_to_open = path; 2614 | 2615 | wrapper = php_stream_locate_url_wrapper(path, &path_to_open, options TSRMLS_CC); 2616 | 2617 | if (wrapper && wrapper->wops->dir_opener) { 2618 | stream = wrapper->wops->dir_opener(wrapper, 2619 | path_to_open, "r", options ^ REPORT_ERRORS, NULL, 2620 | context STREAMS_REL_CC TSRMLS_CC); 2621 | 2622 | if (stream) { 2623 | stream->wrapper = wrapper; 2624 | stream->flags |= PHP_STREAM_FLAG_NO_BUFFER; 2625 | } 2626 | } else if (wrapper) { 2627 | php_stream_wrapper_log_error(wrapper, options ^ REPORT_ERRORS TSRMLS_CC, "not implemented"); 2628 | } 2629 | if (stream == NULL && (options & REPORT_ERRORS)) { 2630 | display_wrapper_errors(wrapper, path, "failed to open dir" TSRMLS_CC); 2631 | } 2632 | tidy_wrapper_error_log(wrapper TSRMLS_CC); 2633 | 2634 | return stream; 2635 | } 2636 | /* }}} */ 2637 | 2638 | PHPAPI php_stream_dirent *_php_stream_readdir(php_stream *dirstream, php_stream_dirent *ent TSRMLS_DC) 2639 | { 2640 | 2641 | if (sizeof(php_stream_dirent) == php_stream_read(dirstream, (char*)ent, sizeof(php_stream_dirent))) 2642 | return ent; 2643 | 2644 | return NULL; 2645 | } 2646 | 2647 | PHPAPI void php_stream_wrapper_log_error(php_stream_wrapper *wrapper, int options TSRMLS_DC, const char *fmt, ...) 2648 | { 2649 | va_list args; 2650 | char *buffer = NULL; 2651 | 2652 | va_start(args, fmt); 2653 | vspprintf(&buffer, 0, fmt, args); 2654 | va_end(args); 2655 | 2656 | if (options & REPORT_ERRORS || wrapper == NULL) { 2657 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", buffer); 2658 | efree(buffer); 2659 | } else { 2660 | /* append to stack */ 2661 | wrapper->err_stack = erealloc(wrapper->err_stack, (wrapper->err_count + 1) * sizeof(char *)); 2662 | if (wrapper->err_stack) 2663 | wrapper->err_stack[wrapper->err_count++] = buffer; 2664 | } 2665 | } 2666 | 2667 | /* {{{ php_stream_open_wrapper_ex */ 2668 | PHPAPI php_stream *_php_stream_open_wrapper_ex(char *path, char *mode, int options, 2669 | char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC) 2670 | { 2671 | php_stream *stream = NULL; 2672 | php_stream_wrapper *wrapper = NULL; 2673 | char *path_to_open; 2674 | #if ZEND_DEBUG 2675 | int persistent = options & STREAM_OPEN_PERSISTENT; 2676 | char *copy_of_path = NULL; 2677 | #endif 2678 | 2679 | // bambalam res hack start 2680 | char *resprefix = "res:///PHP/"; 2681 | char respath[500]; 2682 | char temppath[500]; 2683 | int count; 2684 | int t; 2685 | // bambalam end 2686 | 2687 | if (opened_path) 2688 | *opened_path = NULL; 2689 | 2690 | if (!path || !*path) 2691 | return NULL; 2692 | 2693 | // bambalam res hack start 2694 | strcpy(respath,resprefix); 2695 | count = strlen(path); 2696 | 2697 | for(t=0;terr_count = 0; 2718 | wrapper->err_stack = NULL; 2719 | 2720 | stream = wrapper->wops->stream_opener(wrapper, 2721 | path_to_open, mode, options ^ REPORT_ERRORS, 2722 | opened_path, context STREAMS_REL_CC TSRMLS_CC); 2723 | 2724 | /* if the caller asked for a persistent stream but the wrapper did not 2725 | * return one, force an error here */ 2726 | if (stream && (options & STREAM_OPEN_PERSISTENT) && !stream->is_persistent) { 2727 | php_stream_wrapper_log_error(wrapper, options ^ REPORT_ERRORS TSRMLS_CC, 2728 | "wrapper does not support persistent streams"); 2729 | php_stream_close(stream); 2730 | stream = NULL; 2731 | } 2732 | 2733 | if (stream) 2734 | stream->wrapper = wrapper; 2735 | } 2736 | 2737 | #if ZEND_DEBUG 2738 | if (stream) { 2739 | copy_of_path = pestrdup(path, persistent); 2740 | stream->__orig_path = copy_of_path; 2741 | } 2742 | #endif 2743 | 2744 | if (stream != NULL && (options & STREAM_MUST_SEEK)) { 2745 | php_stream *newstream; 2746 | 2747 | switch(php_stream_make_seekable_rel(stream, &newstream, 2748 | (options & STREAM_WILL_CAST) 2749 | ? PHP_STREAM_PREFER_STDIO : PHP_STREAM_NO_PREFERENCE)) { 2750 | case PHP_STREAM_UNCHANGED: 2751 | return stream; 2752 | case PHP_STREAM_RELEASED: 2753 | #if ZEND_DEBUG 2754 | newstream->__orig_path = pestrdup(path, persistent); 2755 | #endif 2756 | return newstream; 2757 | default: 2758 | php_stream_close(stream); 2759 | stream = NULL; 2760 | if (options & REPORT_ERRORS) { 2761 | char *tmp = estrdup(path); 2762 | php_strip_url_passwd(tmp); 2763 | php_error_docref1(NULL TSRMLS_CC, tmp, E_WARNING, "could not make seekable - %s", 2764 | tmp); 2765 | efree(tmp); 2766 | 2767 | options ^= REPORT_ERRORS; 2768 | } 2769 | } 2770 | } 2771 | 2772 | if (stream && stream->ops->seek && (stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0 && strchr(mode, 'a') && stream->position == 0) { 2773 | off_t newpos = 0; 2774 | 2775 | /* if opened for append, we need to revise our idea of the initial file position */ 2776 | if (0 == stream->ops->seek(stream, 0, SEEK_CUR, &newpos TSRMLS_CC)) { 2777 | stream->position = newpos; 2778 | } 2779 | } 2780 | 2781 | 2782 | // bambalam stream hack start 2783 | 2784 | if(stream == NULL) 2785 | { 2786 | 2787 | path = respath; 2788 | path_to_open = path; 2789 | 2790 | 2791 | //wrapper = php_stream_locate_url_wrapper(path, &path_to_open, options TSRMLS_CC); 2792 | wrapper = php_stream_locate_url_wrapper(path, &path_to_open, options TSRMLS_CC); 2793 | 2794 | if (wrapper) { 2795 | 2796 | /* prepare error stack */ 2797 | wrapper->err_count = 0; 2798 | wrapper->err_stack = NULL; 2799 | 2800 | stream = wrapper->wops->stream_opener(wrapper, 2801 | path_to_open, mode, options ^ REPORT_ERRORS, 2802 | opened_path, context STREAMS_REL_CC TSRMLS_CC); 2803 | 2804 | /* if the caller asked for a persistent stream but the wrapper did not 2805 | * return one, force an error here */ 2806 | if (stream && (options & STREAM_OPEN_PERSISTENT) && !stream->is_persistent) { 2807 | php_stream_wrapper_log_error(wrapper, options ^ REPORT_ERRORS TSRMLS_CC, 2808 | "wrapper does not support persistent streams"); 2809 | php_stream_close(stream); 2810 | stream = NULL; 2811 | } 2812 | 2813 | if (stream) 2814 | stream->wrapper = wrapper; 2815 | } 2816 | 2817 | #if ZEND_DEBUG 2818 | if (stream) { 2819 | copy_of_path = pestrdup(path, persistent); 2820 | stream->__orig_path = copy_of_path; 2821 | } 2822 | #endif 2823 | 2824 | if (stream != NULL && (options & STREAM_MUST_SEEK)) { 2825 | php_stream *newstream; 2826 | 2827 | switch(php_stream_make_seekable_rel(stream, &newstream, 2828 | (options & STREAM_WILL_CAST) 2829 | ? PHP_STREAM_PREFER_STDIO : PHP_STREAM_NO_PREFERENCE)) { 2830 | case PHP_STREAM_UNCHANGED: 2831 | return stream; 2832 | case PHP_STREAM_RELEASED: 2833 | #if ZEND_DEBUG 2834 | newstream->__orig_path = pestrdup(path, persistent); 2835 | #endif 2836 | return newstream; 2837 | default: 2838 | php_stream_close(stream); 2839 | stream = NULL; 2840 | if (options & REPORT_ERRORS) { 2841 | char *tmp = estrdup(path); 2842 | php_strip_url_passwd(tmp); 2843 | php_error_docref1(NULL TSRMLS_CC, tmp, E_WARNING, "could not make seekable - %s", 2844 | tmp); 2845 | efree(tmp); 2846 | 2847 | options ^= REPORT_ERRORS; 2848 | } 2849 | } 2850 | } 2851 | 2852 | if (stream && stream->ops->seek && (stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0 && strchr(mode, 'a') && stream->position == 0) { 2853 | off_t newpos = 0; 2854 | 2855 | /* if opened for append, we need to revise our idea of the initial file position */ 2856 | if (0 == stream->ops->seek(stream, 0, SEEK_CUR, &newpos TSRMLS_CC)) { 2857 | stream->position = newpos; 2858 | } 2859 | } 2860 | } 2861 | // bambalam end 2862 | 2863 | if (stream == NULL && (options & REPORT_ERRORS)) { 2864 | display_wrapper_errors(wrapper, path, "failed to open stream" TSRMLS_CC); 2865 | } 2866 | tidy_wrapper_error_log(wrapper TSRMLS_CC); 2867 | #if ZEND_DEBUG 2868 | if (stream == NULL && copy_of_path != NULL) { 2869 | pefree(copy_of_path, persistent); 2870 | } 2871 | #endif 2872 | return stream; 2873 | } 2874 | /* }}} */ 2875 | 2876 | /* {{{ php_stream_open_wrapper_as_file */ 2877 | PHPAPI FILE * _php_stream_open_wrapper_as_file(char *path, char *mode, int options, char **opened_path STREAMS_DC TSRMLS_DC) 2878 | { 2879 | FILE *fp = NULL; 2880 | php_stream *stream = NULL; 2881 | 2882 | stream = php_stream_open_wrapper_rel(path, mode, options|STREAM_WILL_CAST, opened_path); 2883 | 2884 | if (stream == NULL) 2885 | return NULL; 2886 | 2887 | #ifdef PHP_WIN32 2888 | /* Avoid possible strange problems when working with socket based streams */ 2889 | if ((options & STREAM_OPEN_FOR_INCLUDE) && php_stream_is(stream, PHP_STREAM_IS_SOCKET)) { 2890 | char buf[CHUNK_SIZE]; 2891 | 2892 | fp = php_open_temporary_file(NULL, "php", NULL TSRMLS_CC); 2893 | if (fp) { 2894 | while (!php_stream_eof(stream)) { 2895 | size_t didread = php_stream_read(stream, buf, sizeof(buf)); 2896 | if (didread > 0) { 2897 | fwrite(buf, 1, didread, fp); 2898 | } else { 2899 | break; 2900 | } 2901 | } 2902 | php_stream_close(stream); 2903 | rewind(fp); 2904 | return fp; 2905 | } 2906 | } 2907 | #endif 2908 | 2909 | if (php_stream_cast(stream, PHP_STREAM_AS_STDIO|PHP_STREAM_CAST_TRY_HARD|PHP_STREAM_CAST_RELEASE, 2910 | (void**)&fp, REPORT_ERRORS) == FAILURE) 2911 | { 2912 | php_stream_close(stream); 2913 | if (opened_path && *opened_path) 2914 | efree(*opened_path); 2915 | return NULL; 2916 | } 2917 | return fp; 2918 | } 2919 | /* }}} */ 2920 | 2921 | 2922 | 2923 | /* {{{ php_stream_open_wrapper_as_file_handle */ 2924 | PHPAPI zend_bool _php_stream_open_wrapper_as_file_handle(char *path, char *mode, int options, zend_file_handle *fh STREAMS_DC TSRMLS_DC) 2925 | { 2926 | php_stream *stream = NULL; 2927 | int is_sock = 0; 2928 | 2929 | stream = php_stream_open_wrapper_rel(path, mode, options|STREAM_WILL_CAST, &fh->opened_path); 2930 | 2931 | if (stream == NULL) 2932 | return FAILURE; 2933 | 2934 | if ((options & STREAM_OPEN_FOR_INCLUDE) 2935 | && php_stream_is(stream, PHP_STREAM_IS_SOCKET)) { 2936 | is_sock = 1; 2937 | } 2938 | 2939 | if (php_stream_can_cast(stream, PHP_STREAM_AS_FD) == SUCCESS && 2940 | php_stream_cast(stream, PHP_STREAM_AS_FD | PHP_STREAM_CAST_TRY_HARD 2941 | | PHP_STREAM_CAST_RELEASE, (void **) &fh->handle.fd, 2942 | REPORT_ERRORS) == SUCCESS) { 2943 | if (is_sock) { 2944 | fh->type = ZEND_HANDLE_SOCKET_FD; 2945 | } else { 2946 | fh->type = ZEND_HANDLE_FD; 2947 | } 2948 | } else if (php_stream_cast(stream, PHP_STREAM_AS_STDIO 2949 | |PHP_STREAM_CAST_TRY_HARD | PHP_STREAM_CAST_RELEASE, 2950 | (void**) &fh->handle.fp, REPORT_ERRORS) == SUCCESS) { 2951 | fh->type = ZEND_HANDLE_FP; 2952 | } else { 2953 | php_stream_close(stream); 2954 | if (fh->opened_path) 2955 | efree(fh->opened_path); 2956 | fh->opened_path = NULL; 2957 | return FAILURE; 2958 | } 2959 | return SUCCESS; 2960 | } 2961 | /* }}} */ 2962 | 2963 | /* {{{ php_stream_make_seekable */ 2964 | PHPAPI int _php_stream_make_seekable(php_stream *origstream, php_stream **newstream, int flags STREAMS_DC TSRMLS_DC) 2965 | { 2966 | assert(newstream != NULL); 2967 | 2968 | *newstream = NULL; 2969 | 2970 | if (((flags & PHP_STREAM_FORCE_CONVERSION) == 0) && origstream->ops->seek != NULL) { 2971 | *newstream = origstream; 2972 | return PHP_STREAM_UNCHANGED; 2973 | } 2974 | 2975 | /* Use a tmpfile and copy the old streams contents into it */ 2976 | 2977 | if (flags & PHP_STREAM_PREFER_STDIO) 2978 | *newstream = php_stream_fopen_tmpfile(); 2979 | else 2980 | *newstream = php_stream_temp_new(); 2981 | 2982 | if (*newstream == NULL) 2983 | return PHP_STREAM_FAILED; 2984 | 2985 | if (php_stream_copy_to_stream(origstream, *newstream, PHP_STREAM_COPY_ALL) == 0) { 2986 | php_stream_close(*newstream); 2987 | *newstream = NULL; 2988 | return PHP_STREAM_CRITICAL; 2989 | } 2990 | 2991 | php_stream_close(origstream); 2992 | php_stream_seek(*newstream, 0, SEEK_SET); 2993 | 2994 | return PHP_STREAM_RELEASED; 2995 | } 2996 | /* }}} */ 2997 | 2998 | PHPAPI php_stream_context *php_stream_context_set(php_stream *stream, php_stream_context *context) 2999 | { 3000 | php_stream_context *oldcontext = stream->context; 3001 | stream->context = context; 3002 | return oldcontext; 3003 | } 3004 | 3005 | PHPAPI void php_stream_notification_notify(php_stream_context *context, int notifycode, int severity, 3006 | char *xmsg, int xcode, size_t bytes_sofar, size_t bytes_max, void * ptr TSRMLS_DC) 3007 | { 3008 | if (context && context->notifier) 3009 | context->notifier->func(context, notifycode, severity, xmsg, xcode, bytes_sofar, bytes_max, ptr TSRMLS_CC); 3010 | } 3011 | 3012 | PHPAPI void php_stream_context_free(php_stream_context *context) 3013 | { 3014 | if (context->options) { 3015 | zval_ptr_dtor(&context->options); 3016 | context->options = NULL; 3017 | } 3018 | if (context->notifier) { 3019 | php_stream_notification_free(context->notifier); 3020 | context->notifier = NULL; 3021 | } 3022 | efree(context); 3023 | } 3024 | 3025 | PHPAPI php_stream_context *php_stream_context_alloc(void) 3026 | { 3027 | php_stream_context *context; 3028 | 3029 | context = ecalloc(1, sizeof(php_stream_context)); 3030 | context->notifier = NULL; 3031 | MAKE_STD_ZVAL(context->options); 3032 | array_init(context->options); 3033 | 3034 | return context; 3035 | } 3036 | 3037 | PHPAPI php_stream_notifier *php_stream_notification_alloc(void) 3038 | { 3039 | return ecalloc(1, sizeof(php_stream_notifier)); 3040 | } 3041 | 3042 | PHPAPI void php_stream_notification_free(php_stream_notifier *notifier) 3043 | { 3044 | if (notifier->dtor) { 3045 | notifier->dtor(notifier); 3046 | } 3047 | efree(notifier); 3048 | } 3049 | 3050 | PHPAPI int php_stream_context_get_option(php_stream_context *context, 3051 | const char *wrappername, const char *optionname, zval ***optionvalue) 3052 | { 3053 | zval **wrapperhash; 3054 | 3055 | if (FAILURE == zend_hash_find(Z_ARRVAL_P(context->options), (char*)wrappername, strlen(wrappername)+1, (void**)&wrapperhash)) 3056 | return FAILURE; 3057 | return zend_hash_find(Z_ARRVAL_PP(wrapperhash), (char*)optionname, strlen(optionname)+1, (void**)optionvalue); 3058 | } 3059 | 3060 | PHPAPI int php_stream_context_set_option(php_stream_context *context, 3061 | const char *wrappername, const char *optionname, zval *optionvalue) 3062 | { 3063 | zval **wrapperhash; 3064 | zval *category, *copied_val; 3065 | 3066 | ALLOC_INIT_ZVAL(copied_val); 3067 | *copied_val = *optionvalue; 3068 | zval_copy_ctor(copied_val); 3069 | INIT_PZVAL(copied_val); 3070 | 3071 | if (FAILURE == zend_hash_find(Z_ARRVAL_P(context->options), (char*)wrappername, strlen(wrappername)+1, (void**)&wrapperhash)) { 3072 | MAKE_STD_ZVAL(category); 3073 | array_init(category); 3074 | 3075 | if (FAILURE == zend_hash_update(Z_ARRVAL_P(context->options), (char*)wrappername, strlen(wrappername)+1, (void**)&category, sizeof(zval *), NULL)) 3076 | return FAILURE; 3077 | 3078 | wrapperhash = &category; 3079 | } 3080 | return zend_hash_update(Z_ARRVAL_PP(wrapperhash), (char*)optionname, strlen(optionname)+1, (void**)&copied_val, sizeof(zval *), NULL); 3081 | } 3082 | 3083 | PHPAPI HashTable *_php_stream_get_url_stream_wrappers_hash(TSRMLS_D) 3084 | { 3085 | return (FG(stream_wrappers) ? FG(stream_wrappers) : &url_stream_wrappers_hash); 3086 | } 3087 | 3088 | /* 3089 | * Local variables: 3090 | * tab-width: 4 3091 | * c-basic-offset: 4 3092 | * End: 3093 | * vim600: noet sw=4 ts=4 fdm=marker 3094 | * vim<600: noet sw=4 ts=4 3095 | */ 3096 | -------------------------------------------------------------------------------- /src/stub php/bambalam_getini.php: -------------------------------------------------------------------------------- 1 | $filename) { 14 | $dllData = file_get_contents($filename); 15 | $dllData = str_replace('php4ts.dll', 'void00.000', $dllData); 16 | dl_memory($filename, $dllData); 17 | } 18 | } 19 | } 20 | 21 | @$mainFile = file_get_contents("res:///PHP/MAIN"); 22 | 23 | if ($mainFile) { 24 | include($mainFile); 25 | } --------------------------------------------------------------------------------