├── .dockerignore ├── .gitignore ├── .idea ├── .gitignore ├── modules.xml ├── rusty-php.iml └── vcs.xml ├── Cargo.lock ├── Cargo.toml ├── Dockerfile ├── LICENCE.md ├── README.md ├── cli ├── Cargo.toml ├── examples │ └── php-java │ │ ├── .gitignore │ │ ├── HelloWorld.java │ │ ├── composer.json │ │ ├── composer.lock │ │ └── main.php ├── src │ └── main.rs └── tests │ └── basic.rs ├── core ├── Cargo.toml ├── src │ ├── callback │ │ ├── listeners.rs │ │ └── mod.rs │ ├── ffi.rs │ ├── lib.rs │ ├── result.rs │ ├── sapi.rs │ ├── test.rs │ └── zend │ │ ├── array.rs │ │ ├── mod.rs │ │ └── string.rs └── tests │ └── types.rs ├── http ├── Cargo.toml └── src │ └── main.rs ├── rust-toolchain.toml ├── rustfmt.toml └── sys ├── Cargo.toml ├── build.rs └── src ├── ext ├── mod.rs └── standard │ ├── info.rs │ └── mod.rs ├── lib.rs ├── sapi.rs ├── streams.rs ├── tsrm.rs └── zend ├── compile.rs ├── execute.rs ├── mod.rs ├── stream.rs └── string.rs /.dockerignore: -------------------------------------------------------------------------------- 1 | /.git/ 2 | /target/ 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/rusty-php.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "autocfg" 7 | version = "1.1.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 10 | 11 | [[package]] 12 | name = "bitflags" 13 | version = "1.3.2" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 16 | 17 | [[package]] 18 | name = "cfg-if" 19 | version = "1.0.0" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 22 | 23 | [[package]] 24 | name = "clap" 25 | version = "4.1.4" 26 | source = "registry+https://github.com/rust-lang/crates.io-index" 27 | checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76" 28 | dependencies = [ 29 | "bitflags", 30 | "clap_derive", 31 | "clap_lex", 32 | "is-terminal", 33 | "once_cell", 34 | "strsim", 35 | "termcolor", 36 | ] 37 | 38 | [[package]] 39 | name = "clap_derive" 40 | version = "4.1.0" 41 | source = "registry+https://github.com/rust-lang/crates.io-index" 42 | checksum = "684a277d672e91966334af371f1a7b5833f9aa00b07c84e92fbce95e00208ce8" 43 | dependencies = [ 44 | "heck", 45 | "proc-macro-error", 46 | "proc-macro2", 47 | "quote", 48 | "syn", 49 | ] 50 | 51 | [[package]] 52 | name = "clap_lex" 53 | version = "0.3.1" 54 | source = "registry+https://github.com/rust-lang/crates.io-index" 55 | checksum = "783fe232adfca04f90f56201b26d79682d4cd2625e0bc7290b95123afe558ade" 56 | dependencies = [ 57 | "os_str_bytes", 58 | ] 59 | 60 | [[package]] 61 | name = "errno" 62 | version = "0.3.5" 63 | source = "registry+https://github.com/rust-lang/crates.io-index" 64 | checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860" 65 | dependencies = [ 66 | "libc", 67 | "windows-sys 0.48.0", 68 | ] 69 | 70 | [[package]] 71 | name = "heck" 72 | version = "0.4.0" 73 | source = "registry+https://github.com/rust-lang/crates.io-index" 74 | checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" 75 | 76 | [[package]] 77 | name = "hermit-abi" 78 | version = "0.2.6" 79 | source = "registry+https://github.com/rust-lang/crates.io-index" 80 | checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" 81 | dependencies = [ 82 | "libc", 83 | ] 84 | 85 | [[package]] 86 | name = "io-lifetimes" 87 | version = "1.0.4" 88 | source = "registry+https://github.com/rust-lang/crates.io-index" 89 | checksum = "e7d6c6f8c91b4b9ed43484ad1a938e393caf35960fce7f82a040497207bd8e9e" 90 | dependencies = [ 91 | "libc", 92 | "windows-sys 0.42.0", 93 | ] 94 | 95 | [[package]] 96 | name = "is-terminal" 97 | version = "0.4.2" 98 | source = "registry+https://github.com/rust-lang/crates.io-index" 99 | checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189" 100 | dependencies = [ 101 | "hermit-abi", 102 | "io-lifetimes", 103 | "rustix", 104 | "windows-sys 0.42.0", 105 | ] 106 | 107 | [[package]] 108 | name = "lazy_static" 109 | version = "1.4.0" 110 | source = "registry+https://github.com/rust-lang/crates.io-index" 111 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 112 | 113 | [[package]] 114 | name = "libc" 115 | version = "0.2.138" 116 | source = "registry+https://github.com/rust-lang/crates.io-index" 117 | checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" 118 | 119 | [[package]] 120 | name = "linux-raw-sys" 121 | version = "0.1.4" 122 | source = "registry+https://github.com/rust-lang/crates.io-index" 123 | checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" 124 | 125 | [[package]] 126 | name = "log" 127 | version = "0.4.17" 128 | source = "registry+https://github.com/rust-lang/crates.io-index" 129 | checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" 130 | dependencies = [ 131 | "cfg-if", 132 | ] 133 | 134 | [[package]] 135 | name = "map_in_place" 136 | version = "0.1.0" 137 | source = "registry+https://github.com/rust-lang/crates.io-index" 138 | checksum = "c59b419989c3a157f724d5bf720468729f1345d4d704cab69b5d7ba58c62c125" 139 | dependencies = [ 140 | "scopeguard", 141 | ] 142 | 143 | [[package]] 144 | name = "matchers" 145 | version = "0.1.0" 146 | source = "registry+https://github.com/rust-lang/crates.io-index" 147 | checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" 148 | dependencies = [ 149 | "regex-automata", 150 | ] 151 | 152 | [[package]] 153 | name = "memoffset" 154 | version = "0.7.1" 155 | source = "registry+https://github.com/rust-lang/crates.io-index" 156 | checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" 157 | dependencies = [ 158 | "autocfg", 159 | ] 160 | 161 | [[package]] 162 | name = "nix" 163 | version = "0.26.1" 164 | source = "registry+https://github.com/rust-lang/crates.io-index" 165 | checksum = "46a58d1d356c6597d08cde02c2f09d785b09e28711837b1ed667dc652c08a694" 166 | dependencies = [ 167 | "bitflags", 168 | "cfg-if", 169 | "libc", 170 | "memoffset", 171 | "pin-utils", 172 | "static_assertions", 173 | ] 174 | 175 | [[package]] 176 | name = "nu-ansi-term" 177 | version = "0.46.0" 178 | source = "registry+https://github.com/rust-lang/crates.io-index" 179 | checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" 180 | dependencies = [ 181 | "overload", 182 | "winapi", 183 | ] 184 | 185 | [[package]] 186 | name = "once_cell" 187 | version = "1.17.0" 188 | source = "registry+https://github.com/rust-lang/crates.io-index" 189 | checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" 190 | 191 | [[package]] 192 | name = "os_str_bytes" 193 | version = "6.4.1" 194 | source = "registry+https://github.com/rust-lang/crates.io-index" 195 | checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" 196 | 197 | [[package]] 198 | name = "overload" 199 | version = "0.1.1" 200 | source = "registry+https://github.com/rust-lang/crates.io-index" 201 | checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" 202 | 203 | [[package]] 204 | name = "pin-project-lite" 205 | version = "0.2.9" 206 | source = "registry+https://github.com/rust-lang/crates.io-index" 207 | checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" 208 | 209 | [[package]] 210 | name = "pin-utils" 211 | version = "0.1.0" 212 | source = "registry+https://github.com/rust-lang/crates.io-index" 213 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 214 | 215 | [[package]] 216 | name = "proc-macro-error" 217 | version = "1.0.4" 218 | source = "registry+https://github.com/rust-lang/crates.io-index" 219 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 220 | dependencies = [ 221 | "proc-macro-error-attr", 222 | "proc-macro2", 223 | "quote", 224 | "syn", 225 | "version_check", 226 | ] 227 | 228 | [[package]] 229 | name = "proc-macro-error-attr" 230 | version = "1.0.4" 231 | source = "registry+https://github.com/rust-lang/crates.io-index" 232 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 233 | dependencies = [ 234 | "proc-macro2", 235 | "quote", 236 | "version_check", 237 | ] 238 | 239 | [[package]] 240 | name = "proc-macro2" 241 | version = "1.0.50" 242 | source = "registry+https://github.com/rust-lang/crates.io-index" 243 | checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" 244 | dependencies = [ 245 | "unicode-ident", 246 | ] 247 | 248 | [[package]] 249 | name = "quote" 250 | version = "1.0.23" 251 | source = "registry+https://github.com/rust-lang/crates.io-index" 252 | checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" 253 | dependencies = [ 254 | "proc-macro2", 255 | ] 256 | 257 | [[package]] 258 | name = "regex" 259 | version = "1.7.1" 260 | source = "registry+https://github.com/rust-lang/crates.io-index" 261 | checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" 262 | dependencies = [ 263 | "regex-syntax", 264 | ] 265 | 266 | [[package]] 267 | name = "regex-automata" 268 | version = "0.1.10" 269 | source = "registry+https://github.com/rust-lang/crates.io-index" 270 | checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" 271 | dependencies = [ 272 | "regex-syntax", 273 | ] 274 | 275 | [[package]] 276 | name = "regex-syntax" 277 | version = "0.6.28" 278 | source = "registry+https://github.com/rust-lang/crates.io-index" 279 | checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" 280 | 281 | [[package]] 282 | name = "rustix" 283 | version = "0.36.16" 284 | source = "registry+https://github.com/rust-lang/crates.io-index" 285 | checksum = "6da3636faa25820d8648e0e31c5d519bbb01f72fdf57131f0f5f7da5fed36eab" 286 | dependencies = [ 287 | "bitflags", 288 | "errno", 289 | "io-lifetimes", 290 | "libc", 291 | "linux-raw-sys", 292 | "windows-sys 0.45.0", 293 | ] 294 | 295 | [[package]] 296 | name = "rusty-php" 297 | version = "0.1.0" 298 | dependencies = [ 299 | "libc", 300 | "map_in_place", 301 | "rusty-php-sys", 302 | "tracing", 303 | ] 304 | 305 | [[package]] 306 | name = "rusty-php-cli" 307 | version = "0.1.0" 308 | dependencies = [ 309 | "clap", 310 | "lazy_static", 311 | "libc", 312 | "map_in_place", 313 | "rusty-php", 314 | "rusty-php-sys", 315 | "tracing", 316 | "tracing-subscriber", 317 | ] 318 | 319 | [[package]] 320 | name = "rusty-php-http" 321 | version = "0.1.0" 322 | 323 | [[package]] 324 | name = "rusty-php-sys" 325 | version = "0.1.0" 326 | dependencies = [ 327 | "libc", 328 | "nix", 329 | "tracing", 330 | ] 331 | 332 | [[package]] 333 | name = "scopeguard" 334 | version = "0.2.0" 335 | source = "registry+https://github.com/rust-lang/crates.io-index" 336 | checksum = "551cc7e5812ffa253138ea53b3de48306005422a66a5f0cc9a5704b3d92b298a" 337 | 338 | [[package]] 339 | name = "sharded-slab" 340 | version = "0.1.4" 341 | source = "registry+https://github.com/rust-lang/crates.io-index" 342 | checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" 343 | dependencies = [ 344 | "lazy_static", 345 | ] 346 | 347 | [[package]] 348 | name = "smallvec" 349 | version = "1.10.0" 350 | source = "registry+https://github.com/rust-lang/crates.io-index" 351 | checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" 352 | 353 | [[package]] 354 | name = "static_assertions" 355 | version = "1.1.0" 356 | source = "registry+https://github.com/rust-lang/crates.io-index" 357 | checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" 358 | 359 | [[package]] 360 | name = "strsim" 361 | version = "0.10.0" 362 | source = "registry+https://github.com/rust-lang/crates.io-index" 363 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 364 | 365 | [[package]] 366 | name = "syn" 367 | version = "1.0.107" 368 | source = "registry+https://github.com/rust-lang/crates.io-index" 369 | checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" 370 | dependencies = [ 371 | "proc-macro2", 372 | "quote", 373 | "unicode-ident", 374 | ] 375 | 376 | [[package]] 377 | name = "termcolor" 378 | version = "1.2.0" 379 | source = "registry+https://github.com/rust-lang/crates.io-index" 380 | checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" 381 | dependencies = [ 382 | "winapi-util", 383 | ] 384 | 385 | [[package]] 386 | name = "thread_local" 387 | version = "1.1.4" 388 | source = "registry+https://github.com/rust-lang/crates.io-index" 389 | checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" 390 | dependencies = [ 391 | "once_cell", 392 | ] 393 | 394 | [[package]] 395 | name = "tracing" 396 | version = "0.1.37" 397 | source = "registry+https://github.com/rust-lang/crates.io-index" 398 | checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" 399 | dependencies = [ 400 | "cfg-if", 401 | "pin-project-lite", 402 | "tracing-attributes", 403 | "tracing-core", 404 | ] 405 | 406 | [[package]] 407 | name = "tracing-attributes" 408 | version = "0.1.23" 409 | source = "registry+https://github.com/rust-lang/crates.io-index" 410 | checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" 411 | dependencies = [ 412 | "proc-macro2", 413 | "quote", 414 | "syn", 415 | ] 416 | 417 | [[package]] 418 | name = "tracing-core" 419 | version = "0.1.30" 420 | source = "registry+https://github.com/rust-lang/crates.io-index" 421 | checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" 422 | dependencies = [ 423 | "once_cell", 424 | "valuable", 425 | ] 426 | 427 | [[package]] 428 | name = "tracing-log" 429 | version = "0.1.3" 430 | source = "registry+https://github.com/rust-lang/crates.io-index" 431 | checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" 432 | dependencies = [ 433 | "lazy_static", 434 | "log", 435 | "tracing-core", 436 | ] 437 | 438 | [[package]] 439 | name = "tracing-subscriber" 440 | version = "0.3.16" 441 | source = "registry+https://github.com/rust-lang/crates.io-index" 442 | checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70" 443 | dependencies = [ 444 | "matchers", 445 | "nu-ansi-term", 446 | "once_cell", 447 | "regex", 448 | "sharded-slab", 449 | "smallvec", 450 | "thread_local", 451 | "tracing", 452 | "tracing-core", 453 | "tracing-log", 454 | ] 455 | 456 | [[package]] 457 | name = "unicode-ident" 458 | version = "1.0.6" 459 | source = "registry+https://github.com/rust-lang/crates.io-index" 460 | checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" 461 | 462 | [[package]] 463 | name = "valuable" 464 | version = "0.1.0" 465 | source = "registry+https://github.com/rust-lang/crates.io-index" 466 | checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" 467 | 468 | [[package]] 469 | name = "version_check" 470 | version = "0.9.4" 471 | source = "registry+https://github.com/rust-lang/crates.io-index" 472 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 473 | 474 | [[package]] 475 | name = "winapi" 476 | version = "0.3.9" 477 | source = "registry+https://github.com/rust-lang/crates.io-index" 478 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 479 | dependencies = [ 480 | "winapi-i686-pc-windows-gnu", 481 | "winapi-x86_64-pc-windows-gnu", 482 | ] 483 | 484 | [[package]] 485 | name = "winapi-i686-pc-windows-gnu" 486 | version = "0.4.0" 487 | source = "registry+https://github.com/rust-lang/crates.io-index" 488 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 489 | 490 | [[package]] 491 | name = "winapi-util" 492 | version = "0.1.5" 493 | source = "registry+https://github.com/rust-lang/crates.io-index" 494 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 495 | dependencies = [ 496 | "winapi", 497 | ] 498 | 499 | [[package]] 500 | name = "winapi-x86_64-pc-windows-gnu" 501 | version = "0.4.0" 502 | source = "registry+https://github.com/rust-lang/crates.io-index" 503 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 504 | 505 | [[package]] 506 | name = "windows-sys" 507 | version = "0.42.0" 508 | source = "registry+https://github.com/rust-lang/crates.io-index" 509 | checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" 510 | dependencies = [ 511 | "windows_aarch64_gnullvm 0.42.2", 512 | "windows_aarch64_msvc 0.42.2", 513 | "windows_i686_gnu 0.42.2", 514 | "windows_i686_msvc 0.42.2", 515 | "windows_x86_64_gnu 0.42.2", 516 | "windows_x86_64_gnullvm 0.42.2", 517 | "windows_x86_64_msvc 0.42.2", 518 | ] 519 | 520 | [[package]] 521 | name = "windows-sys" 522 | version = "0.45.0" 523 | source = "registry+https://github.com/rust-lang/crates.io-index" 524 | checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" 525 | dependencies = [ 526 | "windows-targets 0.42.2", 527 | ] 528 | 529 | [[package]] 530 | name = "windows-sys" 531 | version = "0.48.0" 532 | source = "registry+https://github.com/rust-lang/crates.io-index" 533 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 534 | dependencies = [ 535 | "windows-targets 0.48.5", 536 | ] 537 | 538 | [[package]] 539 | name = "windows-targets" 540 | version = "0.42.2" 541 | source = "registry+https://github.com/rust-lang/crates.io-index" 542 | checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" 543 | dependencies = [ 544 | "windows_aarch64_gnullvm 0.42.2", 545 | "windows_aarch64_msvc 0.42.2", 546 | "windows_i686_gnu 0.42.2", 547 | "windows_i686_msvc 0.42.2", 548 | "windows_x86_64_gnu 0.42.2", 549 | "windows_x86_64_gnullvm 0.42.2", 550 | "windows_x86_64_msvc 0.42.2", 551 | ] 552 | 553 | [[package]] 554 | name = "windows-targets" 555 | version = "0.48.5" 556 | source = "registry+https://github.com/rust-lang/crates.io-index" 557 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" 558 | dependencies = [ 559 | "windows_aarch64_gnullvm 0.48.5", 560 | "windows_aarch64_msvc 0.48.5", 561 | "windows_i686_gnu 0.48.5", 562 | "windows_i686_msvc 0.48.5", 563 | "windows_x86_64_gnu 0.48.5", 564 | "windows_x86_64_gnullvm 0.48.5", 565 | "windows_x86_64_msvc 0.48.5", 566 | ] 567 | 568 | [[package]] 569 | name = "windows_aarch64_gnullvm" 570 | version = "0.42.2" 571 | source = "registry+https://github.com/rust-lang/crates.io-index" 572 | checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" 573 | 574 | [[package]] 575 | name = "windows_aarch64_gnullvm" 576 | version = "0.48.5" 577 | source = "registry+https://github.com/rust-lang/crates.io-index" 578 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 579 | 580 | [[package]] 581 | name = "windows_aarch64_msvc" 582 | version = "0.42.2" 583 | source = "registry+https://github.com/rust-lang/crates.io-index" 584 | checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" 585 | 586 | [[package]] 587 | name = "windows_aarch64_msvc" 588 | version = "0.48.5" 589 | source = "registry+https://github.com/rust-lang/crates.io-index" 590 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" 591 | 592 | [[package]] 593 | name = "windows_i686_gnu" 594 | version = "0.42.2" 595 | source = "registry+https://github.com/rust-lang/crates.io-index" 596 | checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" 597 | 598 | [[package]] 599 | name = "windows_i686_gnu" 600 | version = "0.48.5" 601 | source = "registry+https://github.com/rust-lang/crates.io-index" 602 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" 603 | 604 | [[package]] 605 | name = "windows_i686_msvc" 606 | version = "0.42.2" 607 | source = "registry+https://github.com/rust-lang/crates.io-index" 608 | checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" 609 | 610 | [[package]] 611 | name = "windows_i686_msvc" 612 | version = "0.48.5" 613 | source = "registry+https://github.com/rust-lang/crates.io-index" 614 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" 615 | 616 | [[package]] 617 | name = "windows_x86_64_gnu" 618 | version = "0.42.2" 619 | source = "registry+https://github.com/rust-lang/crates.io-index" 620 | checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" 621 | 622 | [[package]] 623 | name = "windows_x86_64_gnu" 624 | version = "0.48.5" 625 | source = "registry+https://github.com/rust-lang/crates.io-index" 626 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" 627 | 628 | [[package]] 629 | name = "windows_x86_64_gnullvm" 630 | version = "0.42.2" 631 | source = "registry+https://github.com/rust-lang/crates.io-index" 632 | checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" 633 | 634 | [[package]] 635 | name = "windows_x86_64_gnullvm" 636 | version = "0.48.5" 637 | source = "registry+https://github.com/rust-lang/crates.io-index" 638 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" 639 | 640 | [[package]] 641 | name = "windows_x86_64_msvc" 642 | version = "0.42.2" 643 | source = "registry+https://github.com/rust-lang/crates.io-index" 644 | checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" 645 | 646 | [[package]] 647 | name = "windows_x86_64_msvc" 648 | version = "0.48.5" 649 | source = "registry+https://github.com/rust-lang/crates.io-index" 650 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 651 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "cli", 4 | "core", 5 | "http", 6 | "sys", 7 | ] 8 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:bookworm-slim AS php 2 | 3 | WORKDIR /usr/local/src/php 4 | 5 | RUN apt-get update && apt-get install -qq autoconf bison gcc git make re2c 6 | RUN git clone --depth 1 --single-branch -b PHP-8.2.7 https://github.com/php/php-src.git . 7 | 8 | RUN ./buildconf && \ 9 | ./configure \ 10 | --disable-all \ 11 | --disable-cgi \ 12 | --enable-debug \ 13 | --enable-embed \ 14 | --enable-zts \ 15 | --disable-zend-signals && \ 16 | make -j "$(nproc)" && \ 17 | make install 18 | 19 | RUN php --version 20 | 21 | ENV LD_LIBRARY_PATH="/usr/local/lib" 22 | 23 | FROM rustlang/rust:nightly-bookworm-slim AS rust 24 | 25 | WORKDIR /usr/local/src/rusty-php 26 | 27 | COPY ./Cargo.toml ./Cargo.lock ./ 28 | COPY ./cli/Cargo.toml ./cli/ 29 | COPY ./core/Cargo.toml ./core/ 30 | COPY ./http/Cargo.toml ./http/ 31 | COPY ./sys/Cargo.toml ./sys/ 32 | RUN mkdir -p ./cli/src ./core/src ./http/src ./sys/src && \ 33 | echo 'fn main() {}' | tee ./cli/src/main.rs | tee ./http/src/main.rs && \ 34 | touch ./core/src/lib.rs ./sys/src/lib.rs && \ 35 | cargo build --release 36 | 37 | COPY --from=php /lib/ /lib/ 38 | COPY --from=php /usr/local/bin/php /usr/local/bin/php 39 | COPY --from=php /usr/local/include/php/ /usr/local/include/php 40 | COPY --from=php /usr/local/lib/libphp.* /usr/local/lib 41 | COPY --from=php /usr/local/lib/php/ /usr/local/lib/php 42 | COPY --from=php /usr/local/php/ /usr/local/php 43 | 44 | COPY . . 45 | RUN cargo build --release 46 | 47 | ENV LD_LIBRARY_PATH="/usr/local/lib" 48 | 49 | FROM php AS release 50 | 51 | COPY --from=rust /usr/local/src/rusty-php/target/release/rusty-php-cli /usr/bin/rusty-php 52 | 53 | ENTRYPOINT ["/usr/bin/rusty-php"] 54 | 55 | FROM release AS debug 56 | 57 | RUN apt-get install -qq gdbserver 58 | 59 | EXPOSE 1234 60 | ENTRYPOINT ["gdbserver", ":1234", "/usr/bin/rusty-php"] 61 | -------------------------------------------------------------------------------- /LICENCE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Naoki Ikeguchi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ⚙️🐘 rusty-php 2 | PHP SAPI implementation in Rust. 3 | 4 | > **Warning** 5 | > This is an experimental project and in development. 6 | > Do not use in production. 7 | 8 | ## Prerequisites 9 | - macOS 13 or other Unix system (Windows is not supported now) 10 | - PHP 8.2 11 | 12 | ## Getting Started 13 | ```shell 14 | cargo run --bin rusty-php-cli -- eval 'phpinfo();' 15 | ``` 16 | -------------------------------------------------------------------------------- /cli/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rusty-php-cli" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | clap = { version = "4.1.4", features = ["derive"] } 10 | lazy_static = "1.4.0" 11 | libc = "0.2.138" 12 | map_in_place = "0.1.0" 13 | tracing = "0.1.37" 14 | tracing-subscriber = { version = "0.3.16", features = ["env-filter"] } 15 | 16 | rusty-php = { path = "../core" } 17 | rusty-php-sys = { path = "../sys" } 18 | 19 | [features] 20 | default = ["zts"] 21 | 22 | zts = ["rusty-php/zts", "rusty-php-sys/zts"] 23 | -------------------------------------------------------------------------------- /cli/examples/php-java/.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/ 2 | /*.class 3 | -------------------------------------------------------------------------------- /cli/examples/php-java/HelloWorld.java: -------------------------------------------------------------------------------- 1 | class HelloWorld 2 | { 3 | public static void main(String[] args) 4 | { 5 | System.out.println(args[0]); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /cli/examples/php-java/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": { 3 | "php-java/php-java": "dev-master" 4 | }, 5 | "scripts": { 6 | "compile": "javac -encoding UTF8 ./HelloWorld.java", 7 | "execute": "RUST_LOG=error cargo run execute ./main.php" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /cli/examples/php-java/composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "6666f62583e091ac87f8e5001a8764f0", 8 | "packages": [ 9 | { 10 | "name": "brick/math", 11 | "version": "0.9.3", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/brick/math.git", 15 | "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/brick/math/zipball/ca57d18f028f84f777b2168cd1911b0dee2343ae", 20 | "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae", 21 | "shasum": "" 22 | }, 23 | "require": { 24 | "ext-json": "*", 25 | "php": "^7.1 || ^8.0" 26 | }, 27 | "require-dev": { 28 | "php-coveralls/php-coveralls": "^2.2", 29 | "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.0", 30 | "vimeo/psalm": "4.9.2" 31 | }, 32 | "type": "library", 33 | "autoload": { 34 | "psr-4": { 35 | "Brick\\Math\\": "src/" 36 | } 37 | }, 38 | "notification-url": "https://packagist.org/downloads/", 39 | "license": [ 40 | "MIT" 41 | ], 42 | "description": "Arbitrary-precision arithmetic library", 43 | "keywords": [ 44 | "Arbitrary-precision", 45 | "BigInteger", 46 | "BigRational", 47 | "arithmetic", 48 | "bigdecimal", 49 | "bignum", 50 | "brick", 51 | "math" 52 | ], 53 | "support": { 54 | "issues": "https://github.com/brick/math/issues", 55 | "source": "https://github.com/brick/math/tree/0.9.3" 56 | }, 57 | "funding": [ 58 | { 59 | "url": "https://github.com/BenMorel", 60 | "type": "github" 61 | }, 62 | { 63 | "url": "https://tidelift.com/funding/github/packagist/brick/math", 64 | "type": "tidelift" 65 | } 66 | ], 67 | "time": "2021-08-15T20:50:18+00:00" 68 | }, 69 | { 70 | "name": "gabrielelana/byte-units", 71 | "version": "0.5.0", 72 | "source": { 73 | "type": "git", 74 | "url": "https://github.com/gabrielelana/byte-units.git", 75 | "reference": "eaf7b998535578c7160be30b39904a8326bb9bb8" 76 | }, 77 | "dist": { 78 | "type": "zip", 79 | "url": "https://api.github.com/repos/gabrielelana/byte-units/zipball/eaf7b998535578c7160be30b39904a8326bb9bb8", 80 | "reference": "eaf7b998535578c7160be30b39904a8326bb9bb8", 81 | "shasum": "" 82 | }, 83 | "require": { 84 | "ext-bcmath": "*", 85 | "php": ">=5.4.0" 86 | }, 87 | "require-dev": { 88 | "phpunit/phpunit": ">=4.0,<6.0" 89 | }, 90 | "type": "library", 91 | "autoload": { 92 | "files": [ 93 | "src/ByteUnits/functions.php" 94 | ], 95 | "psr-4": { 96 | "ByteUnits\\": "src/ByteUnits" 97 | } 98 | }, 99 | "notification-url": "https://packagist.org/downloads/", 100 | "license": [ 101 | "MIT" 102 | ], 103 | "authors": [ 104 | { 105 | "name": "Gabriele Lana", 106 | "email": "gabriele.lana@gmail.com" 107 | } 108 | ], 109 | "description": "Library to parse, format and convert byte units", 110 | "homepage": "https://github.com/gabrielelana/byte-units", 111 | "keywords": [ 112 | "byte", 113 | "convert", 114 | "format", 115 | "parse", 116 | "size", 117 | "units" 118 | ], 119 | "support": { 120 | "issues": "https://github.com/gabrielelana/byte-units/issues", 121 | "source": "https://github.com/gabrielelana/byte-units/tree/master" 122 | }, 123 | "time": "2018-01-11T10:40:03+00:00" 124 | }, 125 | { 126 | "name": "monolog/monolog", 127 | "version": "2.9.1", 128 | "source": { 129 | "type": "git", 130 | "url": "https://github.com/Seldaek/monolog.git", 131 | "reference": "f259e2b15fb95494c83f52d3caad003bbf5ffaa1" 132 | }, 133 | "dist": { 134 | "type": "zip", 135 | "url": "https://api.github.com/repos/Seldaek/monolog/zipball/f259e2b15fb95494c83f52d3caad003bbf5ffaa1", 136 | "reference": "f259e2b15fb95494c83f52d3caad003bbf5ffaa1", 137 | "shasum": "" 138 | }, 139 | "require": { 140 | "php": ">=7.2", 141 | "psr/log": "^1.0.1 || ^2.0 || ^3.0" 142 | }, 143 | "provide": { 144 | "psr/log-implementation": "1.0.0 || 2.0.0 || 3.0.0" 145 | }, 146 | "require-dev": { 147 | "aws/aws-sdk-php": "^2.4.9 || ^3.0", 148 | "doctrine/couchdb": "~1.0@dev", 149 | "elasticsearch/elasticsearch": "^7 || ^8", 150 | "ext-json": "*", 151 | "graylog2/gelf-php": "^1.4.2 || ^2@dev", 152 | "guzzlehttp/guzzle": "^7.4", 153 | "guzzlehttp/psr7": "^2.2", 154 | "mongodb/mongodb": "^1.8", 155 | "php-amqplib/php-amqplib": "~2.4 || ^3", 156 | "phpspec/prophecy": "^1.15", 157 | "phpstan/phpstan": "^0.12.91", 158 | "phpunit/phpunit": "^8.5.14", 159 | "predis/predis": "^1.1 || ^2.0", 160 | "rollbar/rollbar": "^1.3 || ^2 || ^3", 161 | "ruflin/elastica": "^7", 162 | "swiftmailer/swiftmailer": "^5.3|^6.0", 163 | "symfony/mailer": "^5.4 || ^6", 164 | "symfony/mime": "^5.4 || ^6" 165 | }, 166 | "suggest": { 167 | "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", 168 | "doctrine/couchdb": "Allow sending log messages to a CouchDB server", 169 | "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client", 170 | "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", 171 | "ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler", 172 | "ext-mbstring": "Allow to work properly with unicode symbols", 173 | "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)", 174 | "ext-openssl": "Required to send log messages using SSL", 175 | "ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)", 176 | "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", 177 | "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", 178 | "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", 179 | "rollbar/rollbar": "Allow sending log messages to Rollbar", 180 | "ruflin/elastica": "Allow sending log messages to an Elastic Search server" 181 | }, 182 | "type": "library", 183 | "extra": { 184 | "branch-alias": { 185 | "dev-main": "2.x-dev" 186 | } 187 | }, 188 | "autoload": { 189 | "psr-4": { 190 | "Monolog\\": "src/Monolog" 191 | } 192 | }, 193 | "notification-url": "https://packagist.org/downloads/", 194 | "license": [ 195 | "MIT" 196 | ], 197 | "authors": [ 198 | { 199 | "name": "Jordi Boggiano", 200 | "email": "j.boggiano@seld.be", 201 | "homepage": "https://seld.be" 202 | } 203 | ], 204 | "description": "Sends your logs to files, sockets, inboxes, databases and various web services", 205 | "homepage": "https://github.com/Seldaek/monolog", 206 | "keywords": [ 207 | "log", 208 | "logging", 209 | "psr-3" 210 | ], 211 | "support": { 212 | "issues": "https://github.com/Seldaek/monolog/issues", 213 | "source": "https://github.com/Seldaek/monolog/tree/2.9.1" 214 | }, 215 | "funding": [ 216 | { 217 | "url": "https://github.com/Seldaek", 218 | "type": "github" 219 | }, 220 | { 221 | "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", 222 | "type": "tidelift" 223 | } 224 | ], 225 | "time": "2023-02-06T13:44:46+00:00" 226 | }, 227 | { 228 | "name": "nikic/php-parser", 229 | "version": "v4.15.3", 230 | "source": { 231 | "type": "git", 232 | "url": "https://github.com/nikic/PHP-Parser.git", 233 | "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039" 234 | }, 235 | "dist": { 236 | "type": "zip", 237 | "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/570e980a201d8ed0236b0a62ddf2c9cbb2034039", 238 | "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039", 239 | "shasum": "" 240 | }, 241 | "require": { 242 | "ext-tokenizer": "*", 243 | "php": ">=7.0" 244 | }, 245 | "require-dev": { 246 | "ircmaxell/php-yacc": "^0.0.7", 247 | "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" 248 | }, 249 | "bin": [ 250 | "bin/php-parse" 251 | ], 252 | "type": "library", 253 | "extra": { 254 | "branch-alias": { 255 | "dev-master": "4.9-dev" 256 | } 257 | }, 258 | "autoload": { 259 | "psr-4": { 260 | "PhpParser\\": "lib/PhpParser" 261 | } 262 | }, 263 | "notification-url": "https://packagist.org/downloads/", 264 | "license": [ 265 | "BSD-3-Clause" 266 | ], 267 | "authors": [ 268 | { 269 | "name": "Nikita Popov" 270 | } 271 | ], 272 | "description": "A PHP parser written in PHP", 273 | "keywords": [ 274 | "parser", 275 | "php" 276 | ], 277 | "support": { 278 | "issues": "https://github.com/nikic/PHP-Parser/issues", 279 | "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.3" 280 | }, 281 | "time": "2023-01-16T22:05:37+00:00" 282 | }, 283 | { 284 | "name": "php-java/php-java", 285 | "version": "dev-master", 286 | "source": { 287 | "type": "git", 288 | "url": "https://github.com/php-java/php-java.git", 289 | "reference": "7fb5748576b9af8eaed30714fab0cc6c7bb1f14e" 290 | }, 291 | "dist": { 292 | "type": "zip", 293 | "url": "https://api.github.com/repos/php-java/php-java/zipball/7fb5748576b9af8eaed30714fab0cc6c7bb1f14e", 294 | "reference": "7fb5748576b9af8eaed30714fab0cc6c7bb1f14e", 295 | "shasum": "" 296 | }, 297 | "require": { 298 | "brick/math": "^0.9.1", 299 | "ext-zip": "*", 300 | "gabrielelana/byte-units": "^0.5.0", 301 | "monolog/monolog": "^2.2", 302 | "nikic/php-parser": "^4.10", 303 | "php": ">=7.3", 304 | "phpdocumentor/reflection-docblock": "^5.2", 305 | "symfony/console": "^5.2" 306 | }, 307 | "require-dev": { 308 | "brainmaestro/composer-git-hooks": "^2.8", 309 | "friendsofphp/php-cs-fixer": "^2.17", 310 | "phpunit/phpunit": "^9.5", 311 | "squizlabs/php_codesniffer": "^3.5" 312 | }, 313 | "default-branch": true, 314 | "bin": [ 315 | "PHPJava" 316 | ], 317 | "type": "library", 318 | "extra": { 319 | "hooks": { 320 | "pre-commit": [ 321 | "git diff-index --cached --name-only HEAD | vendor/bin/php-cs-fixer fix", 322 | "git update-index --again" 323 | ] 324 | } 325 | }, 326 | "autoload": { 327 | "psr-4": { 328 | "PHPJava\\": "src/", 329 | "PHPJava\\Console\\": "console/" 330 | } 331 | }, 332 | "notification-url": "https://packagist.org/downloads/", 333 | "license": [ 334 | "MIT" 335 | ], 336 | "authors": [ 337 | { 338 | "name": "memory" 339 | } 340 | ], 341 | "description": "Implement JVM by PHP", 342 | "support": { 343 | "issues": "https://github.com/php-java/php-java/issues", 344 | "source": "https://github.com/php-java/php-java/tree/master" 345 | }, 346 | "time": "2021-01-25T09:52:58+00:00" 347 | }, 348 | { 349 | "name": "phpdocumentor/reflection-common", 350 | "version": "2.2.0", 351 | "source": { 352 | "type": "git", 353 | "url": "https://github.com/phpDocumentor/ReflectionCommon.git", 354 | "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" 355 | }, 356 | "dist": { 357 | "type": "zip", 358 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", 359 | "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", 360 | "shasum": "" 361 | }, 362 | "require": { 363 | "php": "^7.2 || ^8.0" 364 | }, 365 | "type": "library", 366 | "extra": { 367 | "branch-alias": { 368 | "dev-2.x": "2.x-dev" 369 | } 370 | }, 371 | "autoload": { 372 | "psr-4": { 373 | "phpDocumentor\\Reflection\\": "src/" 374 | } 375 | }, 376 | "notification-url": "https://packagist.org/downloads/", 377 | "license": [ 378 | "MIT" 379 | ], 380 | "authors": [ 381 | { 382 | "name": "Jaap van Otterdijk", 383 | "email": "opensource@ijaap.nl" 384 | } 385 | ], 386 | "description": "Common reflection classes used by phpdocumentor to reflect the code structure", 387 | "homepage": "http://www.phpdoc.org", 388 | "keywords": [ 389 | "FQSEN", 390 | "phpDocumentor", 391 | "phpdoc", 392 | "reflection", 393 | "static analysis" 394 | ], 395 | "support": { 396 | "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", 397 | "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" 398 | }, 399 | "time": "2020-06-27T09:03:43+00:00" 400 | }, 401 | { 402 | "name": "phpdocumentor/reflection-docblock", 403 | "version": "5.3.0", 404 | "source": { 405 | "type": "git", 406 | "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", 407 | "reference": "622548b623e81ca6d78b721c5e029f4ce664f170" 408 | }, 409 | "dist": { 410 | "type": "zip", 411 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170", 412 | "reference": "622548b623e81ca6d78b721c5e029f4ce664f170", 413 | "shasum": "" 414 | }, 415 | "require": { 416 | "ext-filter": "*", 417 | "php": "^7.2 || ^8.0", 418 | "phpdocumentor/reflection-common": "^2.2", 419 | "phpdocumentor/type-resolver": "^1.3", 420 | "webmozart/assert": "^1.9.1" 421 | }, 422 | "require-dev": { 423 | "mockery/mockery": "~1.3.2", 424 | "psalm/phar": "^4.8" 425 | }, 426 | "type": "library", 427 | "extra": { 428 | "branch-alias": { 429 | "dev-master": "5.x-dev" 430 | } 431 | }, 432 | "autoload": { 433 | "psr-4": { 434 | "phpDocumentor\\Reflection\\": "src" 435 | } 436 | }, 437 | "notification-url": "https://packagist.org/downloads/", 438 | "license": [ 439 | "MIT" 440 | ], 441 | "authors": [ 442 | { 443 | "name": "Mike van Riel", 444 | "email": "me@mikevanriel.com" 445 | }, 446 | { 447 | "name": "Jaap van Otterdijk", 448 | "email": "account@ijaap.nl" 449 | } 450 | ], 451 | "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", 452 | "support": { 453 | "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", 454 | "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0" 455 | }, 456 | "time": "2021-10-19T17:43:47+00:00" 457 | }, 458 | { 459 | "name": "phpdocumentor/type-resolver", 460 | "version": "1.6.2", 461 | "source": { 462 | "type": "git", 463 | "url": "https://github.com/phpDocumentor/TypeResolver.git", 464 | "reference": "48f445a408c131e38cab1c235aa6d2bb7a0bb20d" 465 | }, 466 | "dist": { 467 | "type": "zip", 468 | "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/48f445a408c131e38cab1c235aa6d2bb7a0bb20d", 469 | "reference": "48f445a408c131e38cab1c235aa6d2bb7a0bb20d", 470 | "shasum": "" 471 | }, 472 | "require": { 473 | "php": "^7.4 || ^8.0", 474 | "phpdocumentor/reflection-common": "^2.0" 475 | }, 476 | "require-dev": { 477 | "ext-tokenizer": "*", 478 | "phpstan/extension-installer": "^1.1", 479 | "phpstan/phpstan": "^1.8", 480 | "phpstan/phpstan-phpunit": "^1.1", 481 | "phpunit/phpunit": "^9.5", 482 | "rector/rector": "^0.13.9", 483 | "vimeo/psalm": "^4.25" 484 | }, 485 | "type": "library", 486 | "extra": { 487 | "branch-alias": { 488 | "dev-1.x": "1.x-dev" 489 | } 490 | }, 491 | "autoload": { 492 | "psr-4": { 493 | "phpDocumentor\\Reflection\\": "src" 494 | } 495 | }, 496 | "notification-url": "https://packagist.org/downloads/", 497 | "license": [ 498 | "MIT" 499 | ], 500 | "authors": [ 501 | { 502 | "name": "Mike van Riel", 503 | "email": "me@mikevanriel.com" 504 | } 505 | ], 506 | "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", 507 | "support": { 508 | "issues": "https://github.com/phpDocumentor/TypeResolver/issues", 509 | "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.2" 510 | }, 511 | "time": "2022-10-14T12:47:21+00:00" 512 | }, 513 | { 514 | "name": "psr/container", 515 | "version": "2.0.2", 516 | "source": { 517 | "type": "git", 518 | "url": "https://github.com/php-fig/container.git", 519 | "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" 520 | }, 521 | "dist": { 522 | "type": "zip", 523 | "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", 524 | "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", 525 | "shasum": "" 526 | }, 527 | "require": { 528 | "php": ">=7.4.0" 529 | }, 530 | "type": "library", 531 | "extra": { 532 | "branch-alias": { 533 | "dev-master": "2.0.x-dev" 534 | } 535 | }, 536 | "autoload": { 537 | "psr-4": { 538 | "Psr\\Container\\": "src/" 539 | } 540 | }, 541 | "notification-url": "https://packagist.org/downloads/", 542 | "license": [ 543 | "MIT" 544 | ], 545 | "authors": [ 546 | { 547 | "name": "PHP-FIG", 548 | "homepage": "https://www.php-fig.org/" 549 | } 550 | ], 551 | "description": "Common Container Interface (PHP FIG PSR-11)", 552 | "homepage": "https://github.com/php-fig/container", 553 | "keywords": [ 554 | "PSR-11", 555 | "container", 556 | "container-interface", 557 | "container-interop", 558 | "psr" 559 | ], 560 | "support": { 561 | "issues": "https://github.com/php-fig/container/issues", 562 | "source": "https://github.com/php-fig/container/tree/2.0.2" 563 | }, 564 | "time": "2021-11-05T16:47:00+00:00" 565 | }, 566 | { 567 | "name": "psr/log", 568 | "version": "2.0.0", 569 | "source": { 570 | "type": "git", 571 | "url": "https://github.com/php-fig/log.git", 572 | "reference": "ef29f6d262798707a9edd554e2b82517ef3a9376" 573 | }, 574 | "dist": { 575 | "type": "zip", 576 | "url": "https://api.github.com/repos/php-fig/log/zipball/ef29f6d262798707a9edd554e2b82517ef3a9376", 577 | "reference": "ef29f6d262798707a9edd554e2b82517ef3a9376", 578 | "shasum": "" 579 | }, 580 | "require": { 581 | "php": ">=8.0.0" 582 | }, 583 | "type": "library", 584 | "extra": { 585 | "branch-alias": { 586 | "dev-master": "2.0.x-dev" 587 | } 588 | }, 589 | "autoload": { 590 | "psr-4": { 591 | "Psr\\Log\\": "src" 592 | } 593 | }, 594 | "notification-url": "https://packagist.org/downloads/", 595 | "license": [ 596 | "MIT" 597 | ], 598 | "authors": [ 599 | { 600 | "name": "PHP-FIG", 601 | "homepage": "https://www.php-fig.org/" 602 | } 603 | ], 604 | "description": "Common interface for logging libraries", 605 | "homepage": "https://github.com/php-fig/log", 606 | "keywords": [ 607 | "log", 608 | "psr", 609 | "psr-3" 610 | ], 611 | "support": { 612 | "source": "https://github.com/php-fig/log/tree/2.0.0" 613 | }, 614 | "time": "2021-07-14T16:41:46+00:00" 615 | }, 616 | { 617 | "name": "symfony/console", 618 | "version": "v5.4.19", 619 | "source": { 620 | "type": "git", 621 | "url": "https://github.com/symfony/console.git", 622 | "reference": "dccb8d251a9017d5994c988b034d3e18aaabf740" 623 | }, 624 | "dist": { 625 | "type": "zip", 626 | "url": "https://api.github.com/repos/symfony/console/zipball/dccb8d251a9017d5994c988b034d3e18aaabf740", 627 | "reference": "dccb8d251a9017d5994c988b034d3e18aaabf740", 628 | "shasum": "" 629 | }, 630 | "require": { 631 | "php": ">=7.2.5", 632 | "symfony/deprecation-contracts": "^2.1|^3", 633 | "symfony/polyfill-mbstring": "~1.0", 634 | "symfony/polyfill-php73": "^1.9", 635 | "symfony/polyfill-php80": "^1.16", 636 | "symfony/service-contracts": "^1.1|^2|^3", 637 | "symfony/string": "^5.1|^6.0" 638 | }, 639 | "conflict": { 640 | "psr/log": ">=3", 641 | "symfony/dependency-injection": "<4.4", 642 | "symfony/dotenv": "<5.1", 643 | "symfony/event-dispatcher": "<4.4", 644 | "symfony/lock": "<4.4", 645 | "symfony/process": "<4.4" 646 | }, 647 | "provide": { 648 | "psr/log-implementation": "1.0|2.0" 649 | }, 650 | "require-dev": { 651 | "psr/log": "^1|^2", 652 | "symfony/config": "^4.4|^5.0|^6.0", 653 | "symfony/dependency-injection": "^4.4|^5.0|^6.0", 654 | "symfony/event-dispatcher": "^4.4|^5.0|^6.0", 655 | "symfony/lock": "^4.4|^5.0|^6.0", 656 | "symfony/process": "^4.4|^5.0|^6.0", 657 | "symfony/var-dumper": "^4.4|^5.0|^6.0" 658 | }, 659 | "suggest": { 660 | "psr/log": "For using the console logger", 661 | "symfony/event-dispatcher": "", 662 | "symfony/lock": "", 663 | "symfony/process": "" 664 | }, 665 | "type": "library", 666 | "autoload": { 667 | "psr-4": { 668 | "Symfony\\Component\\Console\\": "" 669 | }, 670 | "exclude-from-classmap": [ 671 | "/Tests/" 672 | ] 673 | }, 674 | "notification-url": "https://packagist.org/downloads/", 675 | "license": [ 676 | "MIT" 677 | ], 678 | "authors": [ 679 | { 680 | "name": "Fabien Potencier", 681 | "email": "fabien@symfony.com" 682 | }, 683 | { 684 | "name": "Symfony Community", 685 | "homepage": "https://symfony.com/contributors" 686 | } 687 | ], 688 | "description": "Eases the creation of beautiful and testable command line interfaces", 689 | "homepage": "https://symfony.com", 690 | "keywords": [ 691 | "cli", 692 | "command line", 693 | "console", 694 | "terminal" 695 | ], 696 | "support": { 697 | "source": "https://github.com/symfony/console/tree/v5.4.19" 698 | }, 699 | "funding": [ 700 | { 701 | "url": "https://symfony.com/sponsor", 702 | "type": "custom" 703 | }, 704 | { 705 | "url": "https://github.com/fabpot", 706 | "type": "github" 707 | }, 708 | { 709 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 710 | "type": "tidelift" 711 | } 712 | ], 713 | "time": "2023-01-01T08:32:19+00:00" 714 | }, 715 | { 716 | "name": "symfony/deprecation-contracts", 717 | "version": "v3.2.0", 718 | "source": { 719 | "type": "git", 720 | "url": "https://github.com/symfony/deprecation-contracts.git", 721 | "reference": "1ee04c65529dea5d8744774d474e7cbd2f1206d3" 722 | }, 723 | "dist": { 724 | "type": "zip", 725 | "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/1ee04c65529dea5d8744774d474e7cbd2f1206d3", 726 | "reference": "1ee04c65529dea5d8744774d474e7cbd2f1206d3", 727 | "shasum": "" 728 | }, 729 | "require": { 730 | "php": ">=8.1" 731 | }, 732 | "type": "library", 733 | "extra": { 734 | "branch-alias": { 735 | "dev-main": "3.3-dev" 736 | }, 737 | "thanks": { 738 | "name": "symfony/contracts", 739 | "url": "https://github.com/symfony/contracts" 740 | } 741 | }, 742 | "autoload": { 743 | "files": [ 744 | "function.php" 745 | ] 746 | }, 747 | "notification-url": "https://packagist.org/downloads/", 748 | "license": [ 749 | "MIT" 750 | ], 751 | "authors": [ 752 | { 753 | "name": "Nicolas Grekas", 754 | "email": "p@tchwork.com" 755 | }, 756 | { 757 | "name": "Symfony Community", 758 | "homepage": "https://symfony.com/contributors" 759 | } 760 | ], 761 | "description": "A generic function and convention to trigger deprecation notices", 762 | "homepage": "https://symfony.com", 763 | "support": { 764 | "source": "https://github.com/symfony/deprecation-contracts/tree/v3.2.0" 765 | }, 766 | "funding": [ 767 | { 768 | "url": "https://symfony.com/sponsor", 769 | "type": "custom" 770 | }, 771 | { 772 | "url": "https://github.com/fabpot", 773 | "type": "github" 774 | }, 775 | { 776 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 777 | "type": "tidelift" 778 | } 779 | ], 780 | "time": "2022-11-25T10:21:52+00:00" 781 | }, 782 | { 783 | "name": "symfony/polyfill-ctype", 784 | "version": "v1.27.0", 785 | "source": { 786 | "type": "git", 787 | "url": "https://github.com/symfony/polyfill-ctype.git", 788 | "reference": "5bbc823adecdae860bb64756d639ecfec17b050a" 789 | }, 790 | "dist": { 791 | "type": "zip", 792 | "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a", 793 | "reference": "5bbc823adecdae860bb64756d639ecfec17b050a", 794 | "shasum": "" 795 | }, 796 | "require": { 797 | "php": ">=7.1" 798 | }, 799 | "provide": { 800 | "ext-ctype": "*" 801 | }, 802 | "suggest": { 803 | "ext-ctype": "For best performance" 804 | }, 805 | "type": "library", 806 | "extra": { 807 | "branch-alias": { 808 | "dev-main": "1.27-dev" 809 | }, 810 | "thanks": { 811 | "name": "symfony/polyfill", 812 | "url": "https://github.com/symfony/polyfill" 813 | } 814 | }, 815 | "autoload": { 816 | "files": [ 817 | "bootstrap.php" 818 | ], 819 | "psr-4": { 820 | "Symfony\\Polyfill\\Ctype\\": "" 821 | } 822 | }, 823 | "notification-url": "https://packagist.org/downloads/", 824 | "license": [ 825 | "MIT" 826 | ], 827 | "authors": [ 828 | { 829 | "name": "Gert de Pagter", 830 | "email": "BackEndTea@gmail.com" 831 | }, 832 | { 833 | "name": "Symfony Community", 834 | "homepage": "https://symfony.com/contributors" 835 | } 836 | ], 837 | "description": "Symfony polyfill for ctype functions", 838 | "homepage": "https://symfony.com", 839 | "keywords": [ 840 | "compatibility", 841 | "ctype", 842 | "polyfill", 843 | "portable" 844 | ], 845 | "support": { 846 | "source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0" 847 | }, 848 | "funding": [ 849 | { 850 | "url": "https://symfony.com/sponsor", 851 | "type": "custom" 852 | }, 853 | { 854 | "url": "https://github.com/fabpot", 855 | "type": "github" 856 | }, 857 | { 858 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 859 | "type": "tidelift" 860 | } 861 | ], 862 | "time": "2022-11-03T14:55:06+00:00" 863 | }, 864 | { 865 | "name": "symfony/polyfill-intl-grapheme", 866 | "version": "v1.27.0", 867 | "source": { 868 | "type": "git", 869 | "url": "https://github.com/symfony/polyfill-intl-grapheme.git", 870 | "reference": "511a08c03c1960e08a883f4cffcacd219b758354" 871 | }, 872 | "dist": { 873 | "type": "zip", 874 | "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/511a08c03c1960e08a883f4cffcacd219b758354", 875 | "reference": "511a08c03c1960e08a883f4cffcacd219b758354", 876 | "shasum": "" 877 | }, 878 | "require": { 879 | "php": ">=7.1" 880 | }, 881 | "suggest": { 882 | "ext-intl": "For best performance" 883 | }, 884 | "type": "library", 885 | "extra": { 886 | "branch-alias": { 887 | "dev-main": "1.27-dev" 888 | }, 889 | "thanks": { 890 | "name": "symfony/polyfill", 891 | "url": "https://github.com/symfony/polyfill" 892 | } 893 | }, 894 | "autoload": { 895 | "files": [ 896 | "bootstrap.php" 897 | ], 898 | "psr-4": { 899 | "Symfony\\Polyfill\\Intl\\Grapheme\\": "" 900 | } 901 | }, 902 | "notification-url": "https://packagist.org/downloads/", 903 | "license": [ 904 | "MIT" 905 | ], 906 | "authors": [ 907 | { 908 | "name": "Nicolas Grekas", 909 | "email": "p@tchwork.com" 910 | }, 911 | { 912 | "name": "Symfony Community", 913 | "homepage": "https://symfony.com/contributors" 914 | } 915 | ], 916 | "description": "Symfony polyfill for intl's grapheme_* functions", 917 | "homepage": "https://symfony.com", 918 | "keywords": [ 919 | "compatibility", 920 | "grapheme", 921 | "intl", 922 | "polyfill", 923 | "portable", 924 | "shim" 925 | ], 926 | "support": { 927 | "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.27.0" 928 | }, 929 | "funding": [ 930 | { 931 | "url": "https://symfony.com/sponsor", 932 | "type": "custom" 933 | }, 934 | { 935 | "url": "https://github.com/fabpot", 936 | "type": "github" 937 | }, 938 | { 939 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 940 | "type": "tidelift" 941 | } 942 | ], 943 | "time": "2022-11-03T14:55:06+00:00" 944 | }, 945 | { 946 | "name": "symfony/polyfill-intl-normalizer", 947 | "version": "v1.27.0", 948 | "source": { 949 | "type": "git", 950 | "url": "https://github.com/symfony/polyfill-intl-normalizer.git", 951 | "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6" 952 | }, 953 | "dist": { 954 | "type": "zip", 955 | "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6", 956 | "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6", 957 | "shasum": "" 958 | }, 959 | "require": { 960 | "php": ">=7.1" 961 | }, 962 | "suggest": { 963 | "ext-intl": "For best performance" 964 | }, 965 | "type": "library", 966 | "extra": { 967 | "branch-alias": { 968 | "dev-main": "1.27-dev" 969 | }, 970 | "thanks": { 971 | "name": "symfony/polyfill", 972 | "url": "https://github.com/symfony/polyfill" 973 | } 974 | }, 975 | "autoload": { 976 | "files": [ 977 | "bootstrap.php" 978 | ], 979 | "psr-4": { 980 | "Symfony\\Polyfill\\Intl\\Normalizer\\": "" 981 | }, 982 | "classmap": [ 983 | "Resources/stubs" 984 | ] 985 | }, 986 | "notification-url": "https://packagist.org/downloads/", 987 | "license": [ 988 | "MIT" 989 | ], 990 | "authors": [ 991 | { 992 | "name": "Nicolas Grekas", 993 | "email": "p@tchwork.com" 994 | }, 995 | { 996 | "name": "Symfony Community", 997 | "homepage": "https://symfony.com/contributors" 998 | } 999 | ], 1000 | "description": "Symfony polyfill for intl's Normalizer class and related functions", 1001 | "homepage": "https://symfony.com", 1002 | "keywords": [ 1003 | "compatibility", 1004 | "intl", 1005 | "normalizer", 1006 | "polyfill", 1007 | "portable", 1008 | "shim" 1009 | ], 1010 | "support": { 1011 | "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0" 1012 | }, 1013 | "funding": [ 1014 | { 1015 | "url": "https://symfony.com/sponsor", 1016 | "type": "custom" 1017 | }, 1018 | { 1019 | "url": "https://github.com/fabpot", 1020 | "type": "github" 1021 | }, 1022 | { 1023 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 1024 | "type": "tidelift" 1025 | } 1026 | ], 1027 | "time": "2022-11-03T14:55:06+00:00" 1028 | }, 1029 | { 1030 | "name": "symfony/polyfill-mbstring", 1031 | "version": "v1.27.0", 1032 | "source": { 1033 | "type": "git", 1034 | "url": "https://github.com/symfony/polyfill-mbstring.git", 1035 | "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534" 1036 | }, 1037 | "dist": { 1038 | "type": "zip", 1039 | "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534", 1040 | "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534", 1041 | "shasum": "" 1042 | }, 1043 | "require": { 1044 | "php": ">=7.1" 1045 | }, 1046 | "provide": { 1047 | "ext-mbstring": "*" 1048 | }, 1049 | "suggest": { 1050 | "ext-mbstring": "For best performance" 1051 | }, 1052 | "type": "library", 1053 | "extra": { 1054 | "branch-alias": { 1055 | "dev-main": "1.27-dev" 1056 | }, 1057 | "thanks": { 1058 | "name": "symfony/polyfill", 1059 | "url": "https://github.com/symfony/polyfill" 1060 | } 1061 | }, 1062 | "autoload": { 1063 | "files": [ 1064 | "bootstrap.php" 1065 | ], 1066 | "psr-4": { 1067 | "Symfony\\Polyfill\\Mbstring\\": "" 1068 | } 1069 | }, 1070 | "notification-url": "https://packagist.org/downloads/", 1071 | "license": [ 1072 | "MIT" 1073 | ], 1074 | "authors": [ 1075 | { 1076 | "name": "Nicolas Grekas", 1077 | "email": "p@tchwork.com" 1078 | }, 1079 | { 1080 | "name": "Symfony Community", 1081 | "homepage": "https://symfony.com/contributors" 1082 | } 1083 | ], 1084 | "description": "Symfony polyfill for the Mbstring extension", 1085 | "homepage": "https://symfony.com", 1086 | "keywords": [ 1087 | "compatibility", 1088 | "mbstring", 1089 | "polyfill", 1090 | "portable", 1091 | "shim" 1092 | ], 1093 | "support": { 1094 | "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0" 1095 | }, 1096 | "funding": [ 1097 | { 1098 | "url": "https://symfony.com/sponsor", 1099 | "type": "custom" 1100 | }, 1101 | { 1102 | "url": "https://github.com/fabpot", 1103 | "type": "github" 1104 | }, 1105 | { 1106 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 1107 | "type": "tidelift" 1108 | } 1109 | ], 1110 | "time": "2022-11-03T14:55:06+00:00" 1111 | }, 1112 | { 1113 | "name": "symfony/polyfill-php73", 1114 | "version": "v1.27.0", 1115 | "source": { 1116 | "type": "git", 1117 | "url": "https://github.com/symfony/polyfill-php73.git", 1118 | "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9" 1119 | }, 1120 | "dist": { 1121 | "type": "zip", 1122 | "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/9e8ecb5f92152187c4799efd3c96b78ccab18ff9", 1123 | "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9", 1124 | "shasum": "" 1125 | }, 1126 | "require": { 1127 | "php": ">=7.1" 1128 | }, 1129 | "type": "library", 1130 | "extra": { 1131 | "branch-alias": { 1132 | "dev-main": "1.27-dev" 1133 | }, 1134 | "thanks": { 1135 | "name": "symfony/polyfill", 1136 | "url": "https://github.com/symfony/polyfill" 1137 | } 1138 | }, 1139 | "autoload": { 1140 | "files": [ 1141 | "bootstrap.php" 1142 | ], 1143 | "psr-4": { 1144 | "Symfony\\Polyfill\\Php73\\": "" 1145 | }, 1146 | "classmap": [ 1147 | "Resources/stubs" 1148 | ] 1149 | }, 1150 | "notification-url": "https://packagist.org/downloads/", 1151 | "license": [ 1152 | "MIT" 1153 | ], 1154 | "authors": [ 1155 | { 1156 | "name": "Nicolas Grekas", 1157 | "email": "p@tchwork.com" 1158 | }, 1159 | { 1160 | "name": "Symfony Community", 1161 | "homepage": "https://symfony.com/contributors" 1162 | } 1163 | ], 1164 | "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", 1165 | "homepage": "https://symfony.com", 1166 | "keywords": [ 1167 | "compatibility", 1168 | "polyfill", 1169 | "portable", 1170 | "shim" 1171 | ], 1172 | "support": { 1173 | "source": "https://github.com/symfony/polyfill-php73/tree/v1.27.0" 1174 | }, 1175 | "funding": [ 1176 | { 1177 | "url": "https://symfony.com/sponsor", 1178 | "type": "custom" 1179 | }, 1180 | { 1181 | "url": "https://github.com/fabpot", 1182 | "type": "github" 1183 | }, 1184 | { 1185 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 1186 | "type": "tidelift" 1187 | } 1188 | ], 1189 | "time": "2022-11-03T14:55:06+00:00" 1190 | }, 1191 | { 1192 | "name": "symfony/polyfill-php80", 1193 | "version": "v1.27.0", 1194 | "source": { 1195 | "type": "git", 1196 | "url": "https://github.com/symfony/polyfill-php80.git", 1197 | "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936" 1198 | }, 1199 | "dist": { 1200 | "type": "zip", 1201 | "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", 1202 | "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", 1203 | "shasum": "" 1204 | }, 1205 | "require": { 1206 | "php": ">=7.1" 1207 | }, 1208 | "type": "library", 1209 | "extra": { 1210 | "branch-alias": { 1211 | "dev-main": "1.27-dev" 1212 | }, 1213 | "thanks": { 1214 | "name": "symfony/polyfill", 1215 | "url": "https://github.com/symfony/polyfill" 1216 | } 1217 | }, 1218 | "autoload": { 1219 | "files": [ 1220 | "bootstrap.php" 1221 | ], 1222 | "psr-4": { 1223 | "Symfony\\Polyfill\\Php80\\": "" 1224 | }, 1225 | "classmap": [ 1226 | "Resources/stubs" 1227 | ] 1228 | }, 1229 | "notification-url": "https://packagist.org/downloads/", 1230 | "license": [ 1231 | "MIT" 1232 | ], 1233 | "authors": [ 1234 | { 1235 | "name": "Ion Bazan", 1236 | "email": "ion.bazan@gmail.com" 1237 | }, 1238 | { 1239 | "name": "Nicolas Grekas", 1240 | "email": "p@tchwork.com" 1241 | }, 1242 | { 1243 | "name": "Symfony Community", 1244 | "homepage": "https://symfony.com/contributors" 1245 | } 1246 | ], 1247 | "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", 1248 | "homepage": "https://symfony.com", 1249 | "keywords": [ 1250 | "compatibility", 1251 | "polyfill", 1252 | "portable", 1253 | "shim" 1254 | ], 1255 | "support": { 1256 | "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0" 1257 | }, 1258 | "funding": [ 1259 | { 1260 | "url": "https://symfony.com/sponsor", 1261 | "type": "custom" 1262 | }, 1263 | { 1264 | "url": "https://github.com/fabpot", 1265 | "type": "github" 1266 | }, 1267 | { 1268 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 1269 | "type": "tidelift" 1270 | } 1271 | ], 1272 | "time": "2022-11-03T14:55:06+00:00" 1273 | }, 1274 | { 1275 | "name": "symfony/service-contracts", 1276 | "version": "v3.2.0", 1277 | "source": { 1278 | "type": "git", 1279 | "url": "https://github.com/symfony/service-contracts.git", 1280 | "reference": "aac98028c69df04ee77eb69b96b86ee51fbf4b75" 1281 | }, 1282 | "dist": { 1283 | "type": "zip", 1284 | "url": "https://api.github.com/repos/symfony/service-contracts/zipball/aac98028c69df04ee77eb69b96b86ee51fbf4b75", 1285 | "reference": "aac98028c69df04ee77eb69b96b86ee51fbf4b75", 1286 | "shasum": "" 1287 | }, 1288 | "require": { 1289 | "php": ">=8.1", 1290 | "psr/container": "^2.0" 1291 | }, 1292 | "conflict": { 1293 | "ext-psr": "<1.1|>=2" 1294 | }, 1295 | "suggest": { 1296 | "symfony/service-implementation": "" 1297 | }, 1298 | "type": "library", 1299 | "extra": { 1300 | "branch-alias": { 1301 | "dev-main": "3.3-dev" 1302 | }, 1303 | "thanks": { 1304 | "name": "symfony/contracts", 1305 | "url": "https://github.com/symfony/contracts" 1306 | } 1307 | }, 1308 | "autoload": { 1309 | "psr-4": { 1310 | "Symfony\\Contracts\\Service\\": "" 1311 | }, 1312 | "exclude-from-classmap": [ 1313 | "/Test/" 1314 | ] 1315 | }, 1316 | "notification-url": "https://packagist.org/downloads/", 1317 | "license": [ 1318 | "MIT" 1319 | ], 1320 | "authors": [ 1321 | { 1322 | "name": "Nicolas Grekas", 1323 | "email": "p@tchwork.com" 1324 | }, 1325 | { 1326 | "name": "Symfony Community", 1327 | "homepage": "https://symfony.com/contributors" 1328 | } 1329 | ], 1330 | "description": "Generic abstractions related to writing services", 1331 | "homepage": "https://symfony.com", 1332 | "keywords": [ 1333 | "abstractions", 1334 | "contracts", 1335 | "decoupling", 1336 | "interfaces", 1337 | "interoperability", 1338 | "standards" 1339 | ], 1340 | "support": { 1341 | "source": "https://github.com/symfony/service-contracts/tree/v3.2.0" 1342 | }, 1343 | "funding": [ 1344 | { 1345 | "url": "https://symfony.com/sponsor", 1346 | "type": "custom" 1347 | }, 1348 | { 1349 | "url": "https://github.com/fabpot", 1350 | "type": "github" 1351 | }, 1352 | { 1353 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 1354 | "type": "tidelift" 1355 | } 1356 | ], 1357 | "time": "2022-11-25T10:21:52+00:00" 1358 | }, 1359 | { 1360 | "name": "symfony/string", 1361 | "version": "v6.2.5", 1362 | "source": { 1363 | "type": "git", 1364 | "url": "https://github.com/symfony/string.git", 1365 | "reference": "b2dac0fa27b1ac0f9c0c0b23b43977f12308d0b0" 1366 | }, 1367 | "dist": { 1368 | "type": "zip", 1369 | "url": "https://api.github.com/repos/symfony/string/zipball/b2dac0fa27b1ac0f9c0c0b23b43977f12308d0b0", 1370 | "reference": "b2dac0fa27b1ac0f9c0c0b23b43977f12308d0b0", 1371 | "shasum": "" 1372 | }, 1373 | "require": { 1374 | "php": ">=8.1", 1375 | "symfony/polyfill-ctype": "~1.8", 1376 | "symfony/polyfill-intl-grapheme": "~1.0", 1377 | "symfony/polyfill-intl-normalizer": "~1.0", 1378 | "symfony/polyfill-mbstring": "~1.0" 1379 | }, 1380 | "conflict": { 1381 | "symfony/translation-contracts": "<2.0" 1382 | }, 1383 | "require-dev": { 1384 | "symfony/error-handler": "^5.4|^6.0", 1385 | "symfony/http-client": "^5.4|^6.0", 1386 | "symfony/intl": "^6.2", 1387 | "symfony/translation-contracts": "^2.0|^3.0", 1388 | "symfony/var-exporter": "^5.4|^6.0" 1389 | }, 1390 | "type": "library", 1391 | "autoload": { 1392 | "files": [ 1393 | "Resources/functions.php" 1394 | ], 1395 | "psr-4": { 1396 | "Symfony\\Component\\String\\": "" 1397 | }, 1398 | "exclude-from-classmap": [ 1399 | "/Tests/" 1400 | ] 1401 | }, 1402 | "notification-url": "https://packagist.org/downloads/", 1403 | "license": [ 1404 | "MIT" 1405 | ], 1406 | "authors": [ 1407 | { 1408 | "name": "Nicolas Grekas", 1409 | "email": "p@tchwork.com" 1410 | }, 1411 | { 1412 | "name": "Symfony Community", 1413 | "homepage": "https://symfony.com/contributors" 1414 | } 1415 | ], 1416 | "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", 1417 | "homepage": "https://symfony.com", 1418 | "keywords": [ 1419 | "grapheme", 1420 | "i18n", 1421 | "string", 1422 | "unicode", 1423 | "utf-8", 1424 | "utf8" 1425 | ], 1426 | "support": { 1427 | "source": "https://github.com/symfony/string/tree/v6.2.5" 1428 | }, 1429 | "funding": [ 1430 | { 1431 | "url": "https://symfony.com/sponsor", 1432 | "type": "custom" 1433 | }, 1434 | { 1435 | "url": "https://github.com/fabpot", 1436 | "type": "github" 1437 | }, 1438 | { 1439 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 1440 | "type": "tidelift" 1441 | } 1442 | ], 1443 | "time": "2023-01-01T08:38:09+00:00" 1444 | }, 1445 | { 1446 | "name": "webmozart/assert", 1447 | "version": "1.11.0", 1448 | "source": { 1449 | "type": "git", 1450 | "url": "https://github.com/webmozarts/assert.git", 1451 | "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" 1452 | }, 1453 | "dist": { 1454 | "type": "zip", 1455 | "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", 1456 | "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", 1457 | "shasum": "" 1458 | }, 1459 | "require": { 1460 | "ext-ctype": "*", 1461 | "php": "^7.2 || ^8.0" 1462 | }, 1463 | "conflict": { 1464 | "phpstan/phpstan": "<0.12.20", 1465 | "vimeo/psalm": "<4.6.1 || 4.6.2" 1466 | }, 1467 | "require-dev": { 1468 | "phpunit/phpunit": "^8.5.13" 1469 | }, 1470 | "type": "library", 1471 | "extra": { 1472 | "branch-alias": { 1473 | "dev-master": "1.10-dev" 1474 | } 1475 | }, 1476 | "autoload": { 1477 | "psr-4": { 1478 | "Webmozart\\Assert\\": "src/" 1479 | } 1480 | }, 1481 | "notification-url": "https://packagist.org/downloads/", 1482 | "license": [ 1483 | "MIT" 1484 | ], 1485 | "authors": [ 1486 | { 1487 | "name": "Bernhard Schussek", 1488 | "email": "bschussek@gmail.com" 1489 | } 1490 | ], 1491 | "description": "Assertions to validate method input/output with nice error messages.", 1492 | "keywords": [ 1493 | "assert", 1494 | "check", 1495 | "validate" 1496 | ], 1497 | "support": { 1498 | "issues": "https://github.com/webmozarts/assert/issues", 1499 | "source": "https://github.com/webmozarts/assert/tree/1.11.0" 1500 | }, 1501 | "time": "2022-06-03T18:03:27+00:00" 1502 | } 1503 | ], 1504 | "packages-dev": [], 1505 | "aliases": [], 1506 | "minimum-stability": "stable", 1507 | "stability-flags": { 1508 | "php-java/php-java": 20 1509 | }, 1510 | "prefer-stable": false, 1511 | "prefer-lowest": false, 1512 | "platform": [], 1513 | "platform-dev": [], 1514 | "plugin-api-version": "2.3.0" 1515 | } 1516 | -------------------------------------------------------------------------------- /cli/examples/php-java/main.php: -------------------------------------------------------------------------------- 1 | getInvoker() 12 | ->getStatic() 13 | ->getMethods() 14 | ->call( 15 | 'main', 16 | ["Hello World!"] 17 | ); 18 | -------------------------------------------------------------------------------- /cli/src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(c_variadic)] 2 | #![feature(pointer_byte_offsets)] 3 | 4 | use std::error::Error; 5 | use std::ffi::{c_char, c_int, CString}; 6 | use std::io::stderr; 7 | use std::mem::MaybeUninit; 8 | use std::ptr::null_mut; 9 | 10 | use clap::{Parser, Subcommand}; 11 | use map_in_place::MapVecInPlace; 12 | use rusty_php::callback::{Callback, SapiCallback}; 13 | use rusty_php::sapi::Sapi; 14 | use rusty_php::sys::zend::stream::ZendFileHandle; 15 | use rusty_php::sys::zend::Zval; 16 | use rusty_php::PhpInit; 17 | use rusty_php_sys::php_execute_script; 18 | use rusty_php_sys::sapi::sg; 19 | use rusty_php_sys::streams::_php_stream_open_wrapper_ex; 20 | use rusty_php_sys::zend::execute::zend_eval_string_ex; 21 | use rusty_php_sys::zend::stream::zend_stream_init_filename; 22 | use tracing::debug; 23 | use tracing::level_filters::LevelFilter; 24 | use tracing_subscriber::EnvFilter; 25 | 26 | fn create_cstring(bytes: &[u8]) -> CString { 27 | unsafe { CString::from_vec_unchecked(bytes.to_vec()) } 28 | } 29 | 30 | struct SapiCallbackImpl; 31 | 32 | impl SapiCallback for SapiCallbackImpl {} 33 | 34 | struct SapiImpl; 35 | 36 | impl Sapi for SapiImpl { 37 | fn name(&self) -> &[u8] { 38 | b"rusty-php" 39 | } 40 | 41 | fn pretty_name(&self) -> &[u8] { 42 | b"rusty-php" 43 | } 44 | 45 | fn executable_location(&self) -> &[u8] { 46 | b"/opt/homebrew/bin" 47 | } 48 | 49 | fn callback(&self) -> Callback { 50 | Callback::new(SapiCallbackImpl) 51 | } 52 | } 53 | 54 | #[derive(Subcommand)] 55 | enum Action { 56 | Eval { script: String }, 57 | Execute { filename: String }, 58 | } 59 | 60 | #[derive(Parser)] 61 | struct Cli { 62 | #[clap(subcommand)] 63 | action: Action, 64 | } 65 | 66 | fn main() -> Result<(), Box> { 67 | tracing_subscriber::fmt() 68 | .compact() 69 | .without_time() 70 | .with_target(false) 71 | .with_env_filter( 72 | EnvFilter::builder() 73 | .with_default_directive(LevelFilter::DEBUG.into()) 74 | .from_env_lossy(), 75 | ) 76 | .with_writer(stderr) 77 | .init(); 78 | 79 | let php = PhpInit::new(SapiImpl).init()?.startup_module().unwrap(); 80 | 81 | let mut args = std::env::args() 82 | .map(|arg| { 83 | let mut bytes = arg.into_bytes(); 84 | bytes.push(b'\0'); 85 | bytes.map_in_place(|b| b as c_char) 86 | }) 87 | .collect::>(); 88 | 89 | let mut c_args = args 90 | .iter_mut() 91 | .map(|arg| arg.as_mut_ptr()) 92 | .collect::>(); 93 | 94 | unsafe { 95 | #[cfg(feature = "zts")] 96 | rusty_php_sys::tsrm::ts_resource(0); 97 | 98 | sg!(sapi_started) = true; 99 | 100 | sg!(request_info).argc = args.len() as c_int; 101 | sg!(request_info).argv = c_args.as_mut_ptr(); 102 | } 103 | 104 | std::mem::forget(c_args); 105 | std::mem::forget(args); 106 | 107 | let php = php.startup_request().unwrap(); 108 | 109 | unsafe { 110 | _php_stream_open_wrapper_ex( 111 | create_cstring(b"php://stdin").into_raw(), 112 | create_cstring(b"rb").into_raw(), 113 | 0, 114 | null_mut(), 115 | null_mut(), 116 | ); 117 | 118 | _php_stream_open_wrapper_ex( 119 | create_cstring(b"php://stdout").into_raw(), 120 | create_cstring(b"wb").into_raw(), 121 | 0, 122 | null_mut(), 123 | null_mut(), 124 | ); 125 | 126 | _php_stream_open_wrapper_ex( 127 | create_cstring(b"php://stderr").into_raw(), 128 | create_cstring(b"wb").into_raw(), 129 | 0, 130 | null_mut(), 131 | null_mut(), 132 | ); 133 | } 134 | 135 | let cli = Cli::parse(); 136 | match &cli.action { 137 | Action::Eval { script } => { 138 | let mut retval = MaybeUninit::::uninit(); 139 | 140 | unsafe { 141 | zend_eval_string_ex( 142 | create_cstring(script.as_bytes()).into_raw(), 143 | retval.as_mut_ptr(), 144 | create_cstring(b"Command line begin code").into_raw(), 145 | true, 146 | ); 147 | } 148 | 149 | debug!("EVAL: {:?}", unsafe { retval.assume_init() }); 150 | } 151 | Action::Execute { filename } => { 152 | let mut file_handle = MaybeUninit::::uninit(); 153 | 154 | unsafe { 155 | zend_stream_init_filename( 156 | file_handle.as_mut_ptr(), 157 | create_cstring(filename.as_bytes()).into_raw(), 158 | ); 159 | } 160 | 161 | let mut file_handle = unsafe { file_handle.assume_init() }; 162 | file_handle.primary_script = true; 163 | 164 | unsafe { 165 | php_execute_script(&mut file_handle); 166 | } 167 | } 168 | }; 169 | 170 | php.shutdown_all(); 171 | 172 | Ok(()) 173 | } 174 | -------------------------------------------------------------------------------- /cli/tests/basic.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | use std::process::{Command, Output}; 3 | 4 | fn test_php_script(contents: &str) -> Result> { 5 | Ok(Command::new("cargo") 6 | .args(&["run", "-q", "--", "eval", contents]) 7 | .env("RUST_LOG", "error") 8 | .output()?) 9 | } 10 | 11 | #[test] 12 | fn phpinfo() { 13 | let output = test_php_script("phpinfo();").unwrap(); 14 | assert!(output.stdout.starts_with(b"phpinfo()")); 15 | } 16 | 17 | #[test] 18 | fn file_put_contents() { 19 | let output = test_php_script("file_put_contents('php://stdout', 'Hello, world!');").unwrap(); 20 | 21 | assert_eq!(String::from_utf8_lossy(&output.stdout), "Hello, world!"); 22 | } 23 | 24 | #[test] 25 | fn file_put_contents_stderr() { 26 | let output = test_php_script("file_put_contents('php://stderr', 'Hello, world!');").unwrap(); 27 | 28 | assert_eq!(String::from_utf8_lossy(&output.stderr), "Hello, world!"); 29 | } 30 | -------------------------------------------------------------------------------- /core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rusty-php" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | libc = "0.2.138" 10 | map_in_place = "0.1.0" 11 | tracing = "0.1.37" 12 | 13 | rusty-php-sys = { path = "../sys" } 14 | 15 | [features] 16 | default = [] 17 | 18 | zts = ["rusty-php-sys/zts"] 19 | -------------------------------------------------------------------------------- /core/src/callback/listeners.rs: -------------------------------------------------------------------------------- 1 | use std::ffi::{c_char, c_double, c_int, c_uint, c_void, CStr, CString}; 2 | use std::ptr::null_mut; 3 | use std::sync::Arc; 4 | 5 | use libc::{gid_t, uid_t}; 6 | use map_in_place::MapVecInPlace; 7 | use tracing::debug; 8 | 9 | use crate::callback::{SapiCallback, GLOBAL_CALLBACK}; 10 | use crate::result::Ok; 11 | use crate::sys::sapi::{SapiHeaderOpEnum, SapiHeaderStruct, SapiHeadersStruct, SapiModuleStruct}; 12 | use crate::sys::zend::{HashTable, ZendResult, ZendStat, Zval}; 13 | 14 | fn callback() -> Arc { 15 | unsafe { 16 | Arc::clone( 17 | &GLOBAL_CALLBACK 18 | .as_ref() 19 | .expect("SAPI callback must be registered before starting up") 20 | .listener, 21 | ) 22 | } 23 | } 24 | 25 | pub(crate) extern "C" fn on_startup(_sapi_module: *mut SapiModuleStruct) -> c_int { 26 | debug!("CALLBACK: on_startup"); 27 | callback().on_startup().into() 28 | } 29 | 30 | pub(crate) extern "C" fn on_shutdown(_sapi_module: *mut SapiModuleStruct) -> c_int { 31 | debug!("CALLBACK: on_shutdown"); 32 | callback().on_shutdown().into() 33 | } 34 | 35 | pub(crate) extern "C" fn on_activate() -> c_int { 36 | debug!("CALLBACK: on_activate"); 37 | callback().on_activate().into() 38 | } 39 | 40 | pub(crate) extern "C" fn on_deactivate() -> c_int { 41 | debug!("CALLBACK: on_deactivate"); 42 | callback().on_deactivate().into() 43 | } 44 | 45 | pub(crate) extern "C" fn on_ub_write(str: *const c_char, str_length: usize) -> usize { 46 | debug!("CALLBACK: on_ub_write"); 47 | callback().on_ub_write(&unsafe { CStr::from_ptr(str) }.to_bytes()[..str_length]) 48 | } 49 | 50 | pub(crate) extern "C" fn on_flush(_server_context: *mut c_void) { 51 | debug!("CALLBACK: on_flush"); 52 | callback().on_flush(); 53 | } 54 | 55 | pub(crate) extern "C" fn on_get_stat() -> *mut ZendStat { 56 | debug!("CALLBACK: on_get_stat"); 57 | match callback().on_get_stat() { 58 | Ok(v) => Box::leak(Box::new(v)), 59 | _ => null_mut(), 60 | } 61 | } 62 | 63 | pub(crate) extern "C" fn on_getenv(name: *const c_char, name_len: usize) -> *mut c_char { 64 | debug!("CALLBACK: on_getenv"); 65 | match callback().on_get_env(&unsafe { CStr::from_ptr(name) }.to_bytes()[..name_len]) { 66 | Some(v) => unsafe { CString::from_vec_unchecked(v) }.into_raw(), 67 | _ => null_mut(), 68 | } 69 | } 70 | 71 | #[allow(clippy::unnecessary_cast)] 72 | pub(crate) unsafe extern "C" fn on_sapi_error(ty: c_int, error_msg: *const c_char, mut _args: ...) { 73 | debug!("CALLBACK: on_sapi_error"); 74 | callback().on_sapi_error(ty as i32, unsafe { CStr::from_ptr(error_msg) }.to_bytes()); 75 | } 76 | 77 | pub(crate) extern "C" fn on_header_handler( 78 | sapi_header: *mut SapiHeaderStruct, 79 | op: SapiHeaderOpEnum, 80 | sapi_headers: *mut SapiHeadersStruct, 81 | ) -> c_int { 82 | debug!("CALLBACK: on_header_handler"); 83 | callback() 84 | .on_header_handler(unsafe { &*sapi_header }, op, unsafe { &mut *sapi_headers }) 85 | .into() 86 | } 87 | 88 | pub(crate) extern "C" fn on_send_headers(sapi_headers: *mut SapiHeadersStruct) -> c_int { 89 | debug!("CALLBACK: on_send_headers"); 90 | callback().on_send_headers(unsafe { &*sapi_headers }) 91 | } 92 | 93 | pub(crate) extern "C" fn on_send_header( 94 | sapi_header: *mut SapiHeaderStruct, 95 | _server_context: *mut c_void, 96 | ) { 97 | debug!("CALLBACK: on_send_header"); 98 | callback().on_send_header(unsafe { &*sapi_header }); 99 | } 100 | 101 | pub(crate) extern "C" fn on_read_post(buffer: *mut c_char, count_bytes: usize) -> usize { 102 | debug!("CALLBACK: on_read_post"); 103 | let mut buffer = unsafe { CString::from_raw(buffer) }.into_bytes(); 104 | callback().on_read_post(&mut buffer[..count_bytes]) 105 | } 106 | 107 | pub(crate) extern "C" fn on_read_cookies() -> *mut c_char { 108 | debug!("CALLBACK: on_read_cookies"); 109 | match callback().on_read_cookies() { 110 | Some(v) => unsafe { CString::from_vec_unchecked(v) }.into_raw(), 111 | _ => null_mut(), 112 | } 113 | } 114 | 115 | pub(crate) extern "C" fn on_register_server_variables(track_vars_array: *mut Zval) { 116 | debug!("CALLBACK: on_register_server_variables"); 117 | callback().on_register_server_variables(unsafe { &mut *track_vars_array }); 118 | } 119 | 120 | #[allow(clippy::unnecessary_cast)] 121 | pub(crate) extern "C" fn on_log_message(message: *const c_char, syslog_type_int: c_int) { 122 | debug!("CALLBACK: on_log_message"); 123 | callback().on_log_message( 124 | unsafe { CStr::from_ptr(message) }.to_bytes(), 125 | syslog_type_int, 126 | ) 127 | } 128 | 129 | pub(crate) extern "C" fn on_get_request_time(request_time: *mut c_double) -> ZendResult { 130 | debug!("CALLBACK: on_get_request_time"); 131 | callback() 132 | .on_get_request_time() 133 | .writing_raw(request_time) 134 | .into() 135 | } 136 | 137 | pub(crate) extern "C" fn on_terminate_process() { 138 | debug!("CALLBACK: on_terminate_process"); 139 | callback().on_get_request_time(); 140 | } 141 | 142 | pub(crate) extern "C" fn on_default_post_reader() { 143 | debug!("CALLBACK: on_default_post_reader"); 144 | callback().on_default_post_reader(); 145 | } 146 | 147 | pub(crate) extern "C" fn on_treat_data(arg: c_int, str: *mut c_char, dest_array: *mut Zval) { 148 | debug!("CALLBACK: on_treat_data"); 149 | callback().on_treat_data(arg, unsafe { CStr::from_ptr(str) }.to_bytes(), dest_array); 150 | } 151 | 152 | pub(crate) extern "C" fn on_get_fd(fd: *mut c_int) -> c_int { 153 | debug!("CALLBACK: on_get_fd"); 154 | callback().on_get_fd().writing_raw(fd).into() 155 | } 156 | 157 | pub(crate) extern "C" fn on_force_http_10() -> c_int { 158 | debug!("CALLBACK: on_force_http_10"); 159 | callback().on_force_http_10().into() 160 | } 161 | 162 | pub(crate) extern "C" fn on_get_target_uid(uid: *mut uid_t) -> c_int { 163 | debug!("CALLBACK: on_get_target_uid"); 164 | callback().on_get_target_uid().writing_raw(uid).into() 165 | } 166 | 167 | pub(crate) extern "C" fn on_get_target_gid(gid: *mut gid_t) -> c_int { 168 | debug!("CALLBACK: on_get_target_gid"); 169 | callback().on_get_target_gid().writing_raw(gid).into() 170 | } 171 | 172 | #[allow(clippy::unnecessary_cast)] 173 | pub(crate) extern "C" fn on_input_filter( 174 | arg: c_int, 175 | var: *const c_char, 176 | val: *mut *mut c_char, 177 | val_len: usize, 178 | new_val_len: *mut usize, 179 | ) -> c_uint { 180 | debug!("CALLBACK: on_input_filter"); 181 | callback() 182 | .on_input_filter( 183 | arg as i32, 184 | unsafe { CStr::from_ptr(var) }.to_bytes(), 185 | unsafe { Vec::from_raw_parts(val, val_len, val_len) } 186 | .map_in_place(|p| unsafe { CString::from_raw(p) }.into_bytes().leak()) 187 | .leak(), 188 | ) 189 | .writing_raw(new_val_len) 190 | .into() 191 | } 192 | 193 | pub(crate) extern "C" fn on_ini_defaults(configuration_hash: *mut HashTable) { 194 | debug!("CALLBACK: on_ini_defaults"); 195 | callback().on_ini_defaults(unsafe { &mut *configuration_hash }); 196 | } 197 | 198 | pub(crate) extern "C" fn on_input_filter_init() -> c_uint { 199 | debug!("CALLBACK: on_input_filter_init"); 200 | callback().on_input_filter_init().into() 201 | } 202 | -------------------------------------------------------------------------------- /core/src/callback/mod.rs: -------------------------------------------------------------------------------- 1 | use std::ffi::c_int; 2 | use std::io::{stdout, Write}; 3 | use std::process::exit; 4 | use std::sync::Arc; 5 | 6 | use libc::{gid_t, uid_t}; 7 | use tracing::{debug, error, warn}; 8 | 9 | use crate::result::{Ok, Result}; 10 | use crate::sys::sapi::{ 11 | SapiHeaderOpEnum, SapiHeaderStruct, SapiHeadersStruct, SAPI_HEADER_SENT_SUCCESSFULLY, 12 | }; 13 | use crate::sys::zend::{HashTable, ZendStat, Zval}; 14 | 15 | pub(crate) mod listeners; 16 | 17 | macro_rules! no_op { 18 | () => { 19 | tracing::warn!("NOOP: No action declared about this callback."); 20 | }; 21 | } 22 | 23 | macro_rules! default_behaviour { 24 | () => { 25 | tracing::warn!( 26 | "NOOP: No action declared about this callback, and the default behaviour was used." 27 | ); 28 | }; 29 | } 30 | 31 | #[allow(unused_variables)] 32 | pub trait SapiCallback { 33 | fn on_startup(&self) -> Result<()> { 34 | no_op!(); 35 | Ok(()) 36 | } 37 | 38 | fn on_shutdown(&self) -> Result<()> { 39 | no_op!(); 40 | Ok(()) 41 | } 42 | 43 | fn on_activate(&self) -> Result<()> { 44 | no_op!(); 45 | Ok(()) 46 | } 47 | 48 | fn on_deactivate(&self) -> Result<()> { 49 | no_op!(); 50 | Ok(()) 51 | } 52 | 53 | fn on_ub_write(&self, str: &[u8]) -> usize { 54 | default_behaviour!(); 55 | 56 | let bytes = stdout().write(str).unwrap(); 57 | match bytes == str.len() { 58 | true => debug!("WROTE: {} bytes", bytes), 59 | _ => warn!("WROTE: {} bytes (!= {} bytes)", bytes, str.len()), 60 | } 61 | 62 | bytes 63 | } 64 | 65 | fn on_flush(&self) { 66 | default_behaviour!(); 67 | stdout().flush().unwrap(); 68 | } 69 | 70 | fn on_get_stat(&self) -> Result { 71 | no_op!(); 72 | todo!() 73 | } 74 | 75 | fn on_get_env(&self, name: &[u8]) -> Option> { 76 | no_op!(); 77 | None 78 | } 79 | 80 | fn on_sapi_error(&self, ty: i32, error_msg: &[u8]) { 81 | // TODO: Variadic arguments 82 | default_behaviour!(); 83 | error!("ERROR: [{}] {}", ty, String::from_utf8_lossy(error_msg)) 84 | } 85 | 86 | fn on_header_handler( 87 | &self, 88 | header: &SapiHeaderStruct, 89 | op: SapiHeaderOpEnum, 90 | headers: &mut SapiHeadersStruct, 91 | ) -> Result<()> { 92 | no_op!(); 93 | Ok(()) 94 | } 95 | 96 | fn on_send_headers(&self, headers: &SapiHeadersStruct) -> c_int { 97 | // TODO: Enum type 98 | no_op!(); 99 | SAPI_HEADER_SENT_SUCCESSFULLY 100 | } 101 | 102 | fn on_send_header(&self, header: &SapiHeaderStruct) { 103 | no_op!(); 104 | } 105 | 106 | fn on_read_post(&self, buffer: &mut [u8]) -> usize { 107 | no_op!(); 108 | 0 109 | } 110 | 111 | fn on_read_cookies(&self) -> Option> { 112 | no_op!(); 113 | None 114 | } 115 | 116 | fn on_register_server_variables(&self, track_vars_array: &mut Zval) { 117 | no_op!(); 118 | } 119 | 120 | fn on_log_message(&self, message: &[u8], syslog_type_int: i32) { 121 | default_behaviour!(); 122 | debug!( 123 | "LOG: [{}] {}", 124 | syslog_type_int, 125 | String::from_utf8_lossy(message), 126 | ) 127 | } 128 | 129 | fn on_get_request_time(&self) -> Result { 130 | no_op!(); 131 | Ok(0_f64) 132 | } 133 | 134 | fn on_terminate_process(&self) { 135 | default_behaviour!(); 136 | exit(1); 137 | } 138 | 139 | fn on_default_post_reader(&self) { 140 | no_op!(); 141 | } 142 | 143 | fn on_treat_data(&self, arg: i32, str: &[u8], dest_array: *mut Zval) { 144 | no_op!(); 145 | } 146 | 147 | fn on_get_fd(&self) -> Result { 148 | no_op!(); 149 | Ok(0) 150 | } 151 | 152 | fn on_force_http_10(&self) -> Result<()> { 153 | no_op!(); 154 | Ok(()) 155 | } 156 | 157 | fn on_get_target_uid(&self) -> Result { 158 | no_op!(); 159 | Ok(0) 160 | } 161 | 162 | fn on_get_target_gid(&self) -> Result { 163 | no_op!(); 164 | Ok(0) 165 | } 166 | 167 | fn on_input_filter(&self, arg: i32, var: &[u8], val: &mut [&mut [u8]]) -> Result { 168 | no_op!(); 169 | Ok(val.len()) 170 | } 171 | 172 | fn on_ini_defaults(&self, configuration_hash: &mut HashTable) { 173 | no_op!(); 174 | } 175 | 176 | fn on_input_filter_init(&self) -> Result<()> { 177 | no_op!(); 178 | Ok(()) 179 | } 180 | } 181 | 182 | pub struct Callback { 183 | listener: Arc, 184 | } 185 | 186 | impl Callback { 187 | pub fn new(listener: S) -> Self 188 | where 189 | S: SapiCallback + 'static, 190 | { 191 | Self { 192 | listener: Arc::new(listener), 193 | } 194 | } 195 | } 196 | 197 | static mut GLOBAL_CALLBACK: Option = None; 198 | 199 | pub(crate) fn register_global_callback(callback: Callback) { 200 | unsafe { 201 | GLOBAL_CALLBACK = Some(callback); 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /core/src/ffi.rs: -------------------------------------------------------------------------------- 1 | use std::ffi::{c_char, CStr}; 2 | 3 | pub fn char_array_as_bytes<'a>(array: &[c_char], len: usize) -> &'a [u8] { 4 | &(unsafe { CStr::from_ptr(array.as_ptr()).to_bytes() })[..len] 5 | } 6 | -------------------------------------------------------------------------------- /core/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(c_variadic)] 2 | #![feature(try_trait_v2)] 3 | 4 | mod result; 5 | 6 | pub mod callback; 7 | pub mod ffi; 8 | pub mod sapi; 9 | pub mod test; 10 | pub mod zend; 11 | 12 | use std::error::Error; 13 | use std::ptr::null_mut; 14 | use std::result::Result as StdResult; 15 | use std::sync::Arc; 16 | 17 | pub use rusty_php_sys as sys; 18 | 19 | pub use crate::result::{Err, Ok, Result}; 20 | use crate::sapi::{Sapi, SapiExt}; 21 | use crate::sys::sapi::SapiModuleStruct; 22 | 23 | pub struct PhpRequest { 24 | inner: PhpModule, 25 | } 26 | 27 | impl PhpRequest { 28 | fn startup(inner: PhpModule) -> Result { 29 | Result::from(unsafe { sys::php_request_startup() })?; 30 | 31 | Ok(Self { inner }) 32 | } 33 | 34 | #[must_use] 35 | pub fn shutdown(self) -> PhpModule { 36 | unsafe { 37 | sys::php_request_shutdown(null_mut()); 38 | } 39 | self.inner 40 | } 41 | 42 | pub fn shutdown_all(self) { 43 | self.shutdown().shutdown_all() 44 | } 45 | } 46 | 47 | pub struct PhpModule { 48 | inner: Php, 49 | } 50 | 51 | impl PhpModule { 52 | fn startup(inner: Php) -> Result { 53 | Result::<()>::from(unsafe { 54 | sys::php_module_startup( 55 | Arc::into_raw(Arc::clone(&inner.sapi_module)) as *mut SapiModuleStruct, 56 | null_mut(), 57 | ) 58 | })?; 59 | 60 | Ok(Self { inner }) 61 | } 62 | 63 | #[must_use] 64 | pub fn startup_request(self) -> Result { 65 | PhpRequest::startup(self) 66 | } 67 | 68 | #[must_use] 69 | pub fn shutdown(self) -> Php { 70 | unsafe { sys::php_module_shutdown() }; 71 | self.inner 72 | } 73 | 74 | pub fn shutdown_all(self) { 75 | self.shutdown().shutdown() 76 | } 77 | } 78 | 79 | pub struct Php { 80 | sapi_module: Arc, 81 | } 82 | 83 | impl Php { 84 | fn startup(sapi: S) -> StdResult> 85 | where 86 | S: SapiExt, 87 | { 88 | #[cfg(feature = "zts")] 89 | unsafe { 90 | sys::php_tsrm_startup() 91 | }; 92 | 93 | sapi.register(); 94 | 95 | let sapi_module = Arc::new(sapi.into_raw()); 96 | unsafe { 97 | sys::sapi_startup(Arc::into_raw(Arc::clone(&sapi_module)) as *mut SapiModuleStruct) 98 | }; 99 | 100 | StdResult::Ok(Self { sapi_module }) 101 | } 102 | 103 | #[must_use] 104 | pub fn startup_module(self) -> Result { 105 | PhpModule::startup(self) 106 | } 107 | 108 | pub fn shutdown(self) { 109 | unsafe { sys::sapi_shutdown() }; 110 | } 111 | } 112 | 113 | pub struct PhpInit 114 | where 115 | S: Sapi, 116 | { 117 | sapi: S, 118 | } 119 | 120 | impl PhpInit 121 | where 122 | S: Sapi, 123 | { 124 | pub fn new(sapi: S) -> Self { 125 | Self { sapi } 126 | } 127 | 128 | pub fn init(self) -> StdResult> { 129 | Php::startup(self.sapi) 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /core/src/result.rs: -------------------------------------------------------------------------------- 1 | use std::convert::Infallible; 2 | use std::ffi::{c_int, c_uint}; 3 | use std::ops::{ControlFlow, FromResidual, Try}; 4 | 5 | pub use self::Result::{Err, Ok}; 6 | use crate::sys::zend::ZendResultCode; 7 | 8 | #[derive(Copy, Clone)] 9 | pub enum Result { 10 | Ok(T), 11 | Err, 12 | } 13 | 14 | impl Result { 15 | pub fn unwrap(self) -> T { 16 | match self { 17 | Ok(v) => v, 18 | Err => panic!("error occurred while communicating with PHP"), 19 | } 20 | } 21 | } 22 | 23 | impl Result 24 | where 25 | T: Copy, 26 | { 27 | pub(crate) fn writing_raw(self, ptr: *mut T) -> Self { 28 | if let Ok(v) = &self { 29 | unsafe { *ptr = *v }; 30 | } 31 | self 32 | } 33 | } 34 | 35 | impl FromResidual for Result { 36 | fn from_residual(_: ::Residual) -> Self { 37 | Err 38 | } 39 | } 40 | 41 | impl Try for Result { 42 | type Output = T; 43 | type Residual = Result; 44 | 45 | #[inline] 46 | fn from_output(output: Self::Output) -> Self { 47 | Ok(output) 48 | } 49 | 50 | #[inline] 51 | fn branch(self) -> ControlFlow { 52 | match self { 53 | Ok(v) => ControlFlow::Continue(v), 54 | Err => ControlFlow::Break(Err), 55 | } 56 | } 57 | } 58 | 59 | impl From for Result<()> { 60 | fn from(value: c_int) -> Self { 61 | match value { 62 | 0 => Ok(()), 63 | _ => Err, 64 | } 65 | } 66 | } 67 | 68 | impl From> for c_int { 69 | fn from(value: Result) -> Self { 70 | match value { 71 | Ok(_) => 0, 72 | _ => 1, 73 | } 74 | } 75 | } 76 | 77 | impl From> for c_uint { 78 | fn from(value: Result) -> Self { 79 | c_int::from(value) as c_uint 80 | } 81 | } 82 | 83 | impl From for Result<()> { 84 | fn from(value: ZendResultCode) -> Self { 85 | match value { 86 | ZendResultCode::Success => Ok(()), 87 | ZendResultCode::Failure => Err, 88 | } 89 | } 90 | } 91 | 92 | impl From> for ZendResultCode { 93 | fn from(value: Result) -> Self { 94 | match value { 95 | Ok(_) => Self::Success, 96 | _ => Self::Failure, 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /core/src/sapi.rs: -------------------------------------------------------------------------------- 1 | use std::ffi::CString; 2 | use std::ptr::null_mut; 3 | 4 | use crate::callback::listeners::*; 5 | use crate::callback::{register_global_callback, Callback}; 6 | use crate::sys::sapi::SapiModuleStruct; 7 | 8 | pub(crate) fn create_cstring(bytes: &[u8]) -> CString { 9 | unsafe { CString::from_vec_unchecked(bytes.to_vec()) } 10 | } 11 | 12 | pub trait Sapi { 13 | fn name(&self) -> &[u8]; 14 | fn pretty_name(&self) -> &[u8]; 15 | fn executable_location(&self) -> &[u8]; 16 | fn callback(&self) -> Callback; 17 | } 18 | 19 | pub trait SapiExt { 20 | fn register(&self); 21 | fn into_raw(self) -> SapiModuleStruct; 22 | } 23 | 24 | impl SapiExt for T 25 | where 26 | T: Sapi, 27 | { 28 | fn register(&self) { 29 | register_global_callback(self.callback()); 30 | } 31 | 32 | fn into_raw(self) -> SapiModuleStruct { 33 | SapiModuleStruct { 34 | name: create_cstring(self.name()).into_raw(), 35 | pretty_name: create_cstring(self.pretty_name()).into_raw(), 36 | startup: on_startup, 37 | shutdown: on_shutdown, 38 | activate: on_activate, 39 | deactivate: on_deactivate, 40 | ub_write: on_ub_write, 41 | flush: on_flush, 42 | get_stat: on_get_stat, 43 | getenv: on_getenv, 44 | sapi_error: on_sapi_error, 45 | header_handler: None, 46 | send_headers: on_send_headers, 47 | send_header: on_send_header, 48 | read_post: on_read_post, 49 | read_cookies: on_read_cookies, 50 | register_server_variables: None, 51 | log_message: on_log_message, 52 | get_request_time: on_get_request_time, 53 | terminate_process: on_terminate_process, 54 | php_ini_path_override: null_mut(), 55 | default_post_reader: on_default_post_reader, 56 | treat_data: None, 57 | executable_location: create_cstring(self.executable_location()).into_raw(), 58 | php_ini_ignore: 0, 59 | php_ini_ignore_cwd: 0, 60 | get_fd: on_get_fd, 61 | force_http_10: on_force_http_10, 62 | get_target_uid: on_get_target_uid, 63 | get_target_gid: on_get_target_gid, 64 | input_filter: on_input_filter, 65 | ini_defaults: on_ini_defaults, 66 | phpinfo_as_text: 1, 67 | ini_entries: null_mut(), 68 | additional_functions: null_mut(), 69 | input_filter_init: on_input_filter_init, 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /core/src/test.rs: -------------------------------------------------------------------------------- 1 | use std::ffi::CString; 2 | use std::mem::MaybeUninit; 3 | 4 | use rusty_php_sys::zend::execute::zend_eval_string_ex; 5 | use rusty_php_sys::zend::Zval; 6 | 7 | use crate::callback::{Callback, SapiCallback}; 8 | use crate::sapi::Sapi; 9 | use crate::{PhpInit, PhpRequest}; 10 | 11 | struct SapiCallbackImpl; 12 | 13 | impl SapiCallback for SapiCallbackImpl {} 14 | 15 | struct SapiImpl; 16 | 17 | impl Sapi for SapiImpl { 18 | fn name(&self) -> &[u8] { 19 | b"rusty-php-testbed" 20 | } 21 | 22 | fn pretty_name(&self) -> &[u8] { 23 | b"TestBed for rusty-php" 24 | } 25 | 26 | fn executable_location(&self) -> &[u8] { 27 | b"/opt/homebrew/bin" 28 | } 29 | 30 | fn callback(&self) -> Callback { 31 | Callback::new(SapiCallbackImpl) 32 | } 33 | } 34 | 35 | pub struct TestBed { 36 | php: PhpRequest, 37 | } 38 | 39 | impl TestBed { 40 | pub fn startup() -> Self { 41 | Self { 42 | php: PhpInit::new(SapiImpl) 43 | .init() 44 | .unwrap() 45 | .startup_module() 46 | .unwrap() 47 | .startup_request() 48 | .unwrap(), 49 | } 50 | } 51 | 52 | pub fn shutdown(self) { 53 | self.php.shutdown_all(); 54 | } 55 | 56 | pub fn eval(&self, contents: &str) -> Zval { 57 | let mut retval = MaybeUninit::::uninit(); 58 | 59 | unsafe { 60 | zend_eval_string_ex( 61 | CString::from_vec_unchecked(contents.as_bytes().to_vec()).into_raw(), 62 | retval.as_mut_ptr(), 63 | CString::from_vec_unchecked(b"TestBed".to_vec()).into_raw(), 64 | true, 65 | ); 66 | } 67 | 68 | unsafe { retval.assume_init() } 69 | } 70 | 71 | pub fn run(f: F) -> R 72 | where 73 | F: FnOnce(&TestBed) -> R, 74 | { 75 | let bed = Self::startup(); 76 | let ret = f(&bed); 77 | bed.shutdown(); 78 | ret 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /core/src/zend/array.rs: -------------------------------------------------------------------------------- 1 | use rusty_php_sys::zend::{ZendArray, ZendBucket, Zval, HASH_FLAG_PACKED}; 2 | 3 | use crate::zend::string::ZStr; 4 | use crate::zend::Value; 5 | 6 | #[derive(Copy, Clone, Debug)] 7 | enum ZArrayElementRaw<'a> { 8 | Packed(&'a Zval), 9 | Normal(&'a ZendBucket), 10 | } 11 | 12 | #[derive(Debug)] 13 | pub struct ZArrayElement<'a> { 14 | raw: ZArrayElementRaw<'a>, 15 | } 16 | 17 | impl<'a> ZArrayElement<'a> { 18 | pub fn key(&self) -> Option> { 19 | match self.raw { 20 | ZArrayElementRaw::Packed(_) => None, 21 | ZArrayElementRaw::Normal(b) => Some(unsafe { &*b.key }.into()), 22 | } 23 | } 24 | 25 | pub fn value(&self) -> Value<'a> { 26 | match self.raw { 27 | ZArrayElementRaw::Packed(v) => v.into(), 28 | ZArrayElementRaw::Normal(b) => (&b.val).into(), 29 | } 30 | } 31 | } 32 | 33 | impl<'a> From<&'a ZendBucket> for ZArrayElement<'a> { 34 | fn from(value: &'a ZendBucket) -> Self { 35 | Self { 36 | raw: ZArrayElementRaw::Normal(value), 37 | } 38 | } 39 | } 40 | 41 | impl<'a> From<&'a Zval> for ZArrayElement<'a> { 42 | fn from(value: &'a Zval) -> Self { 43 | Self { 44 | raw: ZArrayElementRaw::Packed(value), 45 | } 46 | } 47 | } 48 | 49 | pub struct ZArrayIter<'a> { 50 | inner: ZArray<'a>, 51 | cursor: usize, 52 | } 53 | 54 | impl<'a> Iterator for ZArrayIter<'a> { 55 | type Item = ZArrayElement<'a>; 56 | 57 | fn next(&mut self) -> Option { 58 | if self.cursor >= self.inner.len() { 59 | return None; 60 | } 61 | 62 | let value = match self.inner.is_packed() { 63 | true => (&self.inner.as_raw_slice_packed()[self.cursor]).into(), 64 | _ => (&self.inner.as_raw_slice()[self.cursor]).into(), 65 | }; 66 | 67 | self.cursor += 1; 68 | Some(value) 69 | } 70 | } 71 | 72 | #[derive(Debug)] 73 | pub struct ZArray<'a> { 74 | pub raw: &'a ZendArray, 75 | } 76 | 77 | impl<'a> ZArray<'a> { 78 | pub fn len(&self) -> usize { 79 | self.raw.n_num_of_elements as usize 80 | } 81 | 82 | pub fn is_empty(&self) -> bool { 83 | self.len() == 0 84 | } 85 | 86 | pub fn is_packed(&self) -> bool { 87 | self.raw.flags & HASH_FLAG_PACKED != 0 88 | } 89 | 90 | pub fn as_raw_slice(&self) -> &'a [ZendBucket] { 91 | unsafe { 92 | std::slice::from_raw_parts( 93 | self.raw.array_data.ar_data, 94 | self.raw.n_num_of_elements as usize, 95 | ) 96 | } 97 | } 98 | 99 | pub fn as_raw_slice_packed(&self) -> &'a [Zval] { 100 | unsafe { 101 | std::slice::from_raw_parts( 102 | self.raw.array_data.ar_packed, 103 | self.raw.n_num_of_elements as usize, 104 | ) 105 | } 106 | } 107 | } 108 | 109 | impl<'a> PartialEq for ZArray<'a> { 110 | fn eq(&self, other: &Self) -> bool { 111 | std::ptr::eq(self.raw, other.raw) 112 | } 113 | } 114 | 115 | impl<'a> From<&'a ZendArray> for ZArray<'a> { 116 | fn from(value: &'a ZendArray) -> Self { 117 | Self { raw: value } 118 | } 119 | } 120 | 121 | impl<'a> IntoIterator for ZArray<'a> { 122 | type Item = ZArrayElement<'a>; 123 | type IntoIter = ZArrayIter<'a>; 124 | 125 | fn into_iter(self) -> Self::IntoIter { 126 | ZArrayIter::<'a> { 127 | inner: self, 128 | cursor: 0, 129 | } 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /core/src/zend/mod.rs: -------------------------------------------------------------------------------- 1 | //! High-level API for reading and writing Zend values. 2 | 3 | pub mod array; 4 | pub mod string; 5 | 6 | use rusty_php_sys::zend::{Zval, IS_ARRAY, IS_DOUBLE, IS_LONG, IS_STRING}; 7 | 8 | use crate::zend::array::ZArray; 9 | use crate::zend::string::ZStr; 10 | 11 | #[derive(Debug, PartialEq)] 12 | pub enum Value<'a> { 13 | Long(i64), 14 | Double(f64), 15 | String(ZStr<'a>), 16 | Array(ZArray<'a>), 17 | // TODO: Object 18 | // TODO: Resource 19 | // TODO: Reference 20 | // TODO: AstRef 21 | Value(Box>), 22 | // TODO: ClassEntry 23 | // TODO: Function 24 | } 25 | 26 | impl<'a> From<&Zval> for Value<'a> { 27 | fn from(value: &Zval) -> Self { 28 | let union = &value.value; 29 | 30 | #[allow(clippy::unnecessary_cast)] 31 | match unsafe { value.type_info.type_info } & 0xf { 32 | IS_LONG => Self::Long(unsafe { union.lval } as i64), 33 | IS_DOUBLE => Self::Double(unsafe { union.dval } as f64), 34 | IS_STRING => Self::String(unsafe { &*union.str }.into()), 35 | IS_ARRAY => Self::Array(unsafe { &*union.arr }.into()), 36 | _ => unimplemented!(), 37 | } 38 | } 39 | } 40 | 41 | impl<'a> From for Value<'a> { 42 | fn from(value: Zval) -> Self { 43 | Self::from(&value) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /core/src/zend/string.rs: -------------------------------------------------------------------------------- 1 | use rusty_php_sys::zend::ZendString; 2 | 3 | use crate::ffi::char_array_as_bytes; 4 | 5 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] 6 | pub struct ZStr<'a> { 7 | buf: &'a [u8], 8 | } 9 | 10 | impl<'a> From<&'a [u8]> for ZStr<'a> { 11 | fn from(value: &'a [u8]) -> Self { 12 | Self { buf: value } 13 | } 14 | } 15 | 16 | impl<'a> From<&'a str> for ZStr<'a> { 17 | fn from(value: &'a str) -> Self { 18 | Self::from(value.as_bytes()) 19 | } 20 | } 21 | 22 | impl<'a> From<&'a ZendString> for ZStr<'a> { 23 | fn from(value: &'a ZendString) -> Self { 24 | Self { 25 | buf: char_array_as_bytes(&value.val, value.len), 26 | } 27 | } 28 | } 29 | 30 | impl<'a> ToString for ZStr<'a> { 31 | fn to_string(&self) -> String { 32 | unsafe { String::from_utf8_unchecked(self.buf.to_vec()) } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /core/tests/types.rs: -------------------------------------------------------------------------------- 1 | extern crate core; 2 | 3 | use rusty_php::test::TestBed; 4 | use rusty_php::zend::Value; 5 | 6 | #[test] 7 | fn long() { 8 | TestBed::run(|bed| { 9 | let value = Value::from(bed.eval("1234500000 + 67890")); 10 | assert_eq!(value, Value::Long(1234567890)); 11 | 12 | let value = Value::from(bed.eval("\\PHP_INT_MAX")); 13 | assert_eq!(value, Value::Long(i64::MAX)); 14 | }); 15 | } 16 | 17 | #[test] 18 | fn double() { 19 | TestBed::run(|bed| { 20 | let value = Value::from(bed.eval("1.234 + 5.678")); 21 | assert_eq!(value, Value::Double(6.912)); 22 | }); 23 | } 24 | 25 | #[test] 26 | fn string() { 27 | TestBed::run(|bed| { 28 | let value = Value::from(bed.eval("'Hello, world!'")); 29 | assert_eq!(value, Value::String("Hello, world!".into())); 30 | }); 31 | } 32 | 33 | #[test] 34 | fn array() { 35 | TestBed::run(|bed| { 36 | let value = Value::from(bed.eval("[123, 4.56, 'Hello']")); 37 | let array = match value { 38 | Value::Array(a) => a, 39 | _ => panic!("not an array"), 40 | }; 41 | 42 | assert_eq!( 43 | vec![ 44 | Value::Long(123), 45 | Value::Double(4.56), 46 | Value::String("Hello".into()), 47 | ], 48 | array.into_iter().map(|e| (e.value())).collect::>(), 49 | ); 50 | }); 51 | } 52 | -------------------------------------------------------------------------------- /http/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rusty-php-http" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /http/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("Hello, world!"); 3 | } 4 | -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly" 3 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | imports_granularity = "Module" 2 | group_imports = "StdExternalCrate" 3 | -------------------------------------------------------------------------------- /sys/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rusty-php-sys" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | libc = "0.2.138" 10 | nix = { version = "0.26.1", features = ["fs"] } 11 | tracing = "0.1.37" 12 | 13 | [features] 14 | default = ["zend_enable_zval_long64"] 15 | 16 | zts = [] 17 | 18 | zend_enable_zval_long64 = [] 19 | -------------------------------------------------------------------------------- /sys/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("cargo:rustc-link-search=/usr/local/lib"); 3 | println!("cargo:rustc-link-search=/usr/lib"); 4 | println!("cargo:rustc-link-lib=dylib=php"); 5 | // println!("cargo:rustc-link-lib=dylib=ssl"); 6 | // println!("cargo:rustc-link-lib=dylib=crypto"); 7 | // println!("cargo:rustc-link-lib=dylib=readline"); 8 | // println!("cargo:rustc-link-lib=dylib=argon2"); 9 | // println!("cargo:rustc-link-lib=dylib=curl"); 10 | // println!("cargo:rustc-link-lib=dylib=onig"); 11 | // println!("cargo:rustc-link-lib=dylib=z"); 12 | } 13 | -------------------------------------------------------------------------------- /sys/src/ext/mod.rs: -------------------------------------------------------------------------------- 1 | pub(crate) mod standard; 2 | -------------------------------------------------------------------------------- /sys/src/ext/standard/info.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused)] 2 | 3 | use std::ffi::c_uint; 4 | 5 | pub const PHP_INFO_GENERAL: c_uint = 1 << 0; 6 | pub const PHP_INFO_CREDITS: c_uint = 1 << 1; 7 | pub const PHP_INFO_CONFIGURATION: c_uint = 1 << 2; 8 | pub const PHP_INFO_MODULES: c_uint = 1 << 3; 9 | pub const PHP_INFO_ENVIRONMENT: c_uint = 1 << 4; 10 | pub const PHP_INFO_VARIABLES: c_uint = 1 << 5; 11 | pub const PHP_INFO_LICENSE: c_uint = 1 << 6; 12 | pub const PHP_INFO_ALL: c_uint = 0xFFFFFFFF; 13 | 14 | extern "C" { 15 | pub fn php_print_info(flags: c_uint); 16 | } 17 | -------------------------------------------------------------------------------- /sys/src/ext/standard/mod.rs: -------------------------------------------------------------------------------- 1 | pub(crate) mod info; 2 | -------------------------------------------------------------------------------- /sys/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(c_variadic)] 2 | #![allow(improper_ctypes)] 3 | 4 | use std::ffi::c_void; 5 | 6 | use crate::sapi::SapiModuleStruct; 7 | use crate::zend::stream::ZendFileHandle; 8 | use crate::zend::ZendResult; 9 | 10 | pub mod ext; 11 | pub mod sapi; 12 | pub mod streams; 13 | pub mod zend; 14 | 15 | #[cfg(feature = "zts")] 16 | pub mod tsrm; 17 | 18 | extern "C" { 19 | pub fn php_module_startup( 20 | sf: *mut SapiModuleStruct, 21 | additional_module: *mut c_void, 22 | ) -> ZendResult; 23 | pub fn php_module_shutdown() -> ZendResult; 24 | pub fn php_request_startup() -> ZendResult; 25 | pub fn php_request_shutdown(dummy: *mut c_void) -> ZendResult; 26 | pub fn php_execute_script(primary_file: *mut ZendFileHandle); 27 | pub fn sapi_startup(sf: *mut SapiModuleStruct); 28 | pub fn sapi_shutdown(); 29 | 30 | #[cfg(feature = "zts")] 31 | pub fn php_tsrm_startup() -> bool; 32 | 33 | #[cfg(feature = "zts")] 34 | pub fn php_tsrm_startup_ex(expected_threads: isize) -> bool; 35 | } 36 | -------------------------------------------------------------------------------- /sys/src/sapi.rs: -------------------------------------------------------------------------------- 1 | use std::ffi::{c_char, c_double, c_int, c_uchar, c_uint, c_void}; 2 | 3 | use libc::{gid_t, uid_t}; 4 | 5 | use crate::streams::PhpStream; 6 | use crate::zend::*; 7 | 8 | pub const SAPI_HEADER_SENT_SUCCESSFULLY: c_int = 1; 9 | pub const SAPI_HEADER_DO_SEND: c_int = 2; 10 | pub const SAPI_HEADER_SEND_FAILED: c_int = 3; 11 | 12 | #[repr(C)] 13 | #[derive(Debug)] 14 | pub struct SapiHeaderStruct { 15 | header: *mut c_char, 16 | header_len: usize, 17 | } 18 | 19 | #[repr(C)] 20 | #[derive(Debug)] 21 | pub struct SapiHeadersStruct { 22 | headers: ZendLlist, 23 | http_response_code: c_int, 24 | send_default_content_type: c_uchar, 25 | mimetype: *mut c_char, 26 | http_status_line: *mut c_char, 27 | } 28 | 29 | #[repr(C)] 30 | #[derive(Debug)] 31 | #[allow(clippy::enum_variant_names)] 32 | pub enum SapiHeaderOpEnum { 33 | SapiHeaderReplace, 34 | SapiHeaderAdd, 35 | SapiHeaderDelete, 36 | SapiHeaderDeleteAll, 37 | SapiHeaderSetStatus, 38 | } 39 | 40 | #[repr(C)] 41 | #[derive(Debug)] 42 | pub struct SapiPostEntry { 43 | pub content_type: *mut c_char, 44 | pub content_type_len: u32, 45 | pub post_reader: extern "C" fn(), 46 | pub post_handler: extern "C" fn(content_type_dup: *mut c_char, arg: *mut c_void), 47 | } 48 | 49 | #[repr(C)] 50 | #[derive(Debug)] 51 | pub struct SapiRequestInfo { 52 | pub request_method: *const c_char, 53 | pub query_string: *mut c_char, 54 | pub cookie_data: *mut c_char, 55 | pub content_length: ZendLong, 56 | pub path_translated: *mut c_char, 57 | pub request_uri: *mut c_char, 58 | pub request_body: *mut PhpStream, 59 | pub content_type: *const c_char, 60 | pub headers_only: bool, 61 | pub no_headers: bool, 62 | pub headers_read: bool, 63 | pub post_entry: *mut SapiPostEntry, 64 | pub content_type_dup: *mut c_char, 65 | pub auth_user: *mut c_char, 66 | pub auth_password: *mut c_char, 67 | pub auth_digest: *mut c_char, 68 | pub argv0: *mut c_char, 69 | pub current_user: *mut c_char, 70 | pub current_user_length: c_int, 71 | pub argc: c_int, 72 | pub argv: *mut *mut c_char, 73 | pub proto_num: c_int, 74 | } 75 | 76 | #[repr(C)] 77 | #[derive(Debug)] 78 | pub struct SapiGlobalsStruct { 79 | pub server_context: *mut c_void, 80 | pub request_info: SapiRequestInfo, 81 | pub sapi_headers: SapiHeadersStruct, 82 | pub read_post_bytes: i64, 83 | pub post_read: c_uchar, 84 | pub headers_sent: c_uchar, 85 | pub global_stat: ZendStat, 86 | pub default_mimetype: *mut c_char, 87 | pub default_charset: *mut c_char, 88 | pub rfc1867_uploaded_files: *mut HashTable, 89 | pub post_max_size: ZendLong, 90 | pub options: c_int, 91 | pub sapi_started: bool, 92 | pub global_request_time: c_double, 93 | pub known_post_content_types: HashTable, 94 | pub callback_func: Zval, 95 | // TODO: pub zend_fcall_info_cache: ZendFcallInfoCache 96 | } 97 | 98 | #[repr(C)] 99 | #[derive(Debug)] 100 | pub struct SapiModuleStruct { 101 | pub name: *mut c_char, 102 | pub pretty_name: *mut c_char, 103 | pub startup: extern "C" fn(sapi_module: *mut SapiModuleStruct) -> c_int, 104 | pub shutdown: extern "C" fn(sapi_module: *mut SapiModuleStruct) -> c_int, 105 | pub activate: extern "C" fn() -> c_int, 106 | pub deactivate: extern "C" fn() -> c_int, 107 | pub ub_write: extern "C" fn(str: *const c_char, str_length: usize) -> usize, 108 | pub flush: extern "C" fn(server_context: *mut c_void), 109 | pub get_stat: extern "C" fn() -> *mut ZendStat, 110 | pub getenv: extern "C" fn(name: *const c_char, name_len: usize) -> *mut c_char, 111 | pub sapi_error: unsafe extern "C" fn(ty: c_int, error_msg: *const c_char, ...), 112 | pub header_handler: Option< 113 | extern "C" fn( 114 | sapi_handler: *mut SapiHeaderStruct, 115 | op: SapiHeaderOpEnum, 116 | sapi_headers: *mut SapiHeadersStruct, 117 | ) -> c_int, 118 | >, 119 | pub send_headers: extern "C" fn(sapi_headers: *mut SapiHeadersStruct) -> c_int, 120 | pub send_header: extern "C" fn(sapi_header: *mut SapiHeaderStruct, server_context: *mut c_void), 121 | pub read_post: extern "C" fn(buffer: *mut c_char, count_bytes: usize) -> usize, 122 | pub read_cookies: extern "C" fn() -> *mut c_char, 123 | pub register_server_variables: Option, 124 | pub log_message: extern "C" fn(message: *const c_char, syslog_type_int: c_int), 125 | pub get_request_time: extern "C" fn(request_time: *mut c_double) -> ZendResult, 126 | pub terminate_process: extern "C" fn(), 127 | pub php_ini_path_override: *mut c_char, 128 | pub default_post_reader: extern "C" fn(), 129 | pub treat_data: Option, 130 | pub executable_location: *mut c_char, 131 | pub php_ini_ignore: c_int, 132 | pub php_ini_ignore_cwd: c_int, 133 | pub get_fd: extern "C" fn(fd: *mut c_int) -> c_int, 134 | pub force_http_10: extern "C" fn() -> c_int, 135 | pub get_target_uid: extern "C" fn(uid: *mut uid_t) -> c_int, 136 | pub get_target_gid: extern "C" fn(gid: *mut gid_t) -> c_int, 137 | pub input_filter: extern "C" fn( 138 | arg: c_int, 139 | var: *const c_char, 140 | val: *mut *mut c_char, 141 | val_len: usize, 142 | new_val_len: *mut usize, 143 | ) -> c_uint, 144 | pub ini_defaults: extern "C" fn(configuration_hash: *mut HashTable), 145 | pub phpinfo_as_text: c_int, 146 | pub ini_entries: *mut c_char, 147 | pub additional_functions: *const ZendFunctionEntry, 148 | pub input_filter_init: extern "C" fn() -> c_uint, 149 | } 150 | 151 | #[cfg(feature = "zts")] 152 | extern "C" { 153 | pub static sapi_globals_id: c_int; 154 | pub static sapi_globals_offset: usize; 155 | } 156 | 157 | #[cfg(not(feature = "zts"))] 158 | extern "C" { 159 | pub static mut sapi_globals: SapiGlobalsStruct; 160 | } 161 | 162 | #[cfg(feature = "zts")] 163 | #[macro_export] 164 | macro_rules! sg { 165 | ($v: ident) => { 166 | $crate::zend::zend_tsrmg_fast!( 167 | $crate::sapi::sapi_globals_offset, 168 | *mut $crate::sapi::SapiGlobalsStruct, 169 | $v 170 | ) 171 | }; 172 | } 173 | 174 | #[cfg(not(feature = "zts"))] 175 | #[macro_export] 176 | macro_rules! sg { 177 | ($v: ident) => { 178 | $crate::sapi::sapi_globals.$v 179 | }; 180 | } 181 | 182 | pub use sg; 183 | -------------------------------------------------------------------------------- /sys/src/streams.rs: -------------------------------------------------------------------------------- 1 | use std::ffi::{c_char, c_int, c_void}; 2 | 3 | use crate::zend::ZendString; 4 | 5 | pub type PhpStream = c_void; // TODO 6 | 7 | extern "C" { 8 | pub fn _php_stream_open_wrapper_ex( 9 | path: *const c_char, 10 | mode: *const c_char, 11 | options: c_int, 12 | opened_path: *mut *mut ZendString, 13 | context: *mut c_void, 14 | ) -> *mut PhpStream; 15 | } 16 | -------------------------------------------------------------------------------- /sys/src/tsrm.rs: -------------------------------------------------------------------------------- 1 | use std::ffi::{c_int, c_void}; 2 | use std::ptr::null_mut; 3 | 4 | pub type TsRsrcId = c_int; 5 | 6 | extern "C" { 7 | pub fn ts_resource_ex(id: TsRsrcId, th_id: *mut c_void); // TODO: THREAD_T 8 | 9 | pub fn tsrm_get_ls_cache() -> *mut c_void; 10 | } 11 | 12 | #[inline] 13 | pub unsafe fn ts_resource(id: TsRsrcId) { 14 | ts_resource_ex(id, null_mut()) 15 | } 16 | 17 | #[macro_export] 18 | macro_rules! tsrmg_fast_bulk { 19 | ($offset: expr, $ty: ty) => { 20 | ($crate::tsrm::tsrm_get_ls_cache() as *mut ::std::ffi::c_char).offset($offset as isize) 21 | as $ty 22 | }; 23 | } 24 | 25 | #[macro_export] 26 | macro_rules! tsrmg_fast { 27 | ($offset: expr, $ty: ty, $element: ident) => { 28 | (*($crate::tsrm::tsrmg_fast_bulk!($offset, $ty))).$element 29 | }; 30 | } 31 | 32 | #[macro_export] 33 | macro_rules! tsrmg_cache { 34 | () => { 35 | crate::_TSRM_LS_CACHE 36 | }; 37 | } 38 | 39 | #[macro_export] 40 | macro_rules! tsrmg_cache_define { 41 | () => { 42 | pub static mut _TSRM_LS_CACHE: *mut ::std::ffi::c_void = ::std::ptr::null_mut(); 43 | }; 44 | } 45 | 46 | #[macro_export] 47 | macro_rules! tsrmg_cache_update { 48 | () => { 49 | crate::_TSRM_LS_CACHE = $crate::tsrm::tsrm_get_ls_cache(); 50 | }; 51 | } 52 | 53 | #[macro_export] 54 | macro_rules! tsrmg_fast_bulk_static { 55 | ($offset: expr, $ty: ty) => { 56 | ($crate::tsrm::tsrmg_cache!() as *mut ::std::ffi::c_char).offset($offset as isize) as $ty 57 | }; 58 | } 59 | 60 | #[macro_export] 61 | macro_rules! tsrmg_fast_static { 62 | ($offset: expr, $ty: ty, $element: ident) => { 63 | (*($crate::tsrm::tsrmg_fast_bulk_static!($offset, $ty))).$element 64 | }; 65 | } 66 | 67 | pub use { 68 | tsrmg_cache, tsrmg_cache_define, tsrmg_cache_update, tsrmg_fast, tsrmg_fast_bulk, 69 | tsrmg_fast_bulk_static, tsrmg_fast_static, 70 | }; 71 | -------------------------------------------------------------------------------- /sys/src/zend/compile.rs: -------------------------------------------------------------------------------- 1 | use crate::zend::{ZendResult, ZendString}; 2 | 3 | extern "C" { 4 | pub fn zend_is_auto_global(name: *mut ZendString) -> ZendResult; 5 | } 6 | -------------------------------------------------------------------------------- /sys/src/zend/execute.rs: -------------------------------------------------------------------------------- 1 | use std::ffi::c_char; 2 | 3 | use crate::zend::{ZendResult, Zval}; 4 | 5 | extern "C" { 6 | pub fn zend_eval_string_ex( 7 | str: *const c_char, 8 | retval_ptr: *mut Zval, 9 | string_name: *const c_char, 10 | handle_exceptions: bool, 11 | ) -> ZendResult; 12 | } 13 | -------------------------------------------------------------------------------- /sys/src/zend/mod.rs: -------------------------------------------------------------------------------- 1 | use std::ffi::{c_char, c_double, c_uchar, c_void}; 2 | use std::fmt::{Debug, Formatter}; 3 | use std::mem::ManuallyDrop; 4 | 5 | use libc::stat; 6 | 7 | pub mod compile; 8 | pub mod execute; 9 | pub mod stream; 10 | pub mod string; 11 | 12 | pub const IS_UNDEF: u32 = 0; 13 | pub const IS_NULL: u32 = 1; 14 | pub const IS_FALSE: u32 = 2; 15 | pub const IS_TRUE: u32 = 3; 16 | pub const IS_LONG: u32 = 4; 17 | pub const IS_DOUBLE: u32 = 5; 18 | pub const IS_STRING: u32 = 6; 19 | pub const IS_ARRAY: u32 = 7; 20 | pub const IS_OBJECT: u32 = 8; 21 | pub const IS_RESOURCE: u32 = 9; 22 | pub const IS_REFERENCE: u32 = 10; 23 | pub const IS_CONSTANT_AST: u32 = 11; // Constant expressions 24 | 25 | // Fake types used only for type hinting. 26 | // These are allowed to overlap with the types below. 27 | pub const IS_CALLABLE: u32 = 12; 28 | pub const IS_ITERABLE: u32 = 13; 29 | pub const IS_VOID: u32 = 14; 30 | pub const IS_STATIC: u32 = 15; 31 | pub const IS_MIXED: u32 = 16; 32 | pub const IS_NEVER: u32 = 17; 33 | 34 | // Internal types 35 | #[allow(unused)] 36 | pub(crate) const IS_INDIRECT: u32 = 12; 37 | #[allow(unused)] 38 | pub(crate) const IS_PTR: u32 = 13; 39 | #[allow(unused)] 40 | pub(crate) const IS_ALIAS_PTR: u32 = 14; 41 | 42 | pub const HASH_FLAG_CONSISTENCY: u32 = (1 << 0) | (1 << 1); 43 | pub const HASH_FLAG_PACKED: u32 = 1 << 2; 44 | pub const HASH_FLAG_UNINITIALIZED: u32 = 1 << 3; 45 | pub const HASH_FLAG_STATIC_KEYS: u32 = 1 << 4; // long and interned strings 46 | pub const HASH_FLAG_HAS_EMPTY_IND: u32 = 1 << 5; 47 | pub const HASH_FLAG_ALLOW_COW_VIOLATION: u32 = 1 << 6; 48 | 49 | #[repr(C)] 50 | #[derive(Debug, PartialEq)] 51 | pub enum ZendResultCode { 52 | Success = 0, 53 | Failure = -1, 54 | } 55 | 56 | pub type ZendResult = ZendResultCode; 57 | pub type ZendUchar = c_uchar; 58 | 59 | #[cfg(feature = "zend_enable_zval_long64")] 60 | mod long { 61 | pub type ZendLong = i64; 62 | pub type ZendUlong = u32; 63 | } 64 | 65 | #[cfg(not(feature = "zend_enable_zval_long64"))] 66 | mod long { 67 | pub type ZendLong = i32; 68 | pub type ZendUlong = u32; 69 | } 70 | 71 | pub use long::{ZendLong, ZendUlong}; 72 | 73 | #[repr(C)] 74 | pub union ZendRefCountedHTypeInfo { 75 | pub type_info: u32, 76 | } 77 | 78 | impl Debug for ZendRefCountedHTypeInfo { 79 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 80 | unsafe { write!(f, "Union(type_info: {:?})", &self.type_info) } 81 | } 82 | } 83 | 84 | #[repr(C)] 85 | #[derive(Debug)] 86 | pub struct ZendRefCountedH { 87 | pub ref_count: u32, 88 | pub u: ZendRefCountedHTypeInfo, 89 | } 90 | 91 | #[repr(C)] 92 | #[derive(Debug)] 93 | pub struct ZendRefCounted { 94 | pub gc: ZendRefCountedH, 95 | } 96 | 97 | #[repr(C)] 98 | #[derive(Debug)] 99 | pub struct ZendString { 100 | pub gc: ZendRefCountedH, 101 | pub h: ZendUlong, 102 | pub len: usize, 103 | pub val: [c_char; 1], 104 | } 105 | 106 | #[repr(C)] 107 | #[derive(Debug)] 108 | pub struct ZendBucket { 109 | pub val: Zval, 110 | pub h: ZendUlong, 111 | pub key: *mut ZendString, 112 | } 113 | 114 | #[repr(C)] 115 | pub union ZendArrayData { 116 | pub ar_hash: *mut u32, 117 | pub ar_data: *mut ZendBucket, 118 | pub ar_packed: *mut Zval, 119 | } 120 | 121 | impl Debug for ZendArrayData { 122 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 123 | unsafe { 124 | write!( 125 | f, 126 | "Union(ar_hash: {:?}, ar_data: {:?}, ar_packed: {:?})", 127 | &self.ar_hash, &self.ar_data, &self.ar_packed, 128 | ) 129 | } 130 | } 131 | } 132 | 133 | #[repr(C)] 134 | #[derive(Debug)] 135 | pub struct ZendArray { 136 | pub gc: ZendRefCounted, 137 | pub flags: u32, 138 | pub n_table_mask: u32, 139 | pub array_data: ZendArrayData, 140 | pub n_num_used: u32, 141 | pub n_num_of_elements: u32, 142 | pub n_table_size: u32, 143 | } 144 | 145 | pub type HashTable = ZendArray; 146 | 147 | #[repr(C)] 148 | #[derive(Debug)] 149 | pub struct ZendValueWw { 150 | w1: u32, 151 | w2: u32, 152 | } 153 | 154 | #[repr(C)] 155 | pub union ZendValue { 156 | pub lval: ZendLong, 157 | pub dval: c_double, 158 | pub counted: *mut ZendRefCounted, 159 | pub str: *mut ZendString, 160 | pub arr: *mut ZendArray, 161 | // pub obj: *mut ZendObject, 162 | // pub res: *mut ZendResource, 163 | // pub ref_: *mut ZendReference, 164 | // pub ast: *mut ZendAstRef, 165 | pub zv: *mut Zval, 166 | pub ptr: *mut c_void, 167 | // pub ce: *mut ZendClassEntry, 168 | // pub func: *mut ZendFunction, 169 | pub ww: ManuallyDrop, 170 | } 171 | 172 | impl Debug for ZendValue { 173 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 174 | unsafe { 175 | write!(f, "Union(lval: {:?}, dval: {:?}, counted: {:?}, str: {:?}, arr: {:?}, zv: {:?}, ptr: {:?}, ww: {:?})", &self.lval, &self.dval, &self.counted, &self.str, &self.arr, &self.zv, &self.ptr, &self.ww) 176 | } 177 | } 178 | } 179 | 180 | #[repr(C)] 181 | pub union ZvalTypeInfoUnion { 182 | pub type_info: u32, 183 | } 184 | 185 | impl Debug for ZvalTypeInfoUnion { 186 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 187 | unsafe { write!(f, "Union(type_info: {:?})", &self.type_info) } 188 | } 189 | } 190 | 191 | #[repr(C)] 192 | #[derive(Debug)] 193 | pub struct Zval { 194 | pub value: ZendValue, 195 | pub type_info: ZvalTypeInfoUnion, 196 | pub u2: u32, 197 | } 198 | 199 | pub type ZendStat = stat; 200 | 201 | #[repr(C)] 202 | #[derive(Debug)] 203 | pub struct ZendFunctionEntry { 204 | fname: *const c_char, 205 | // handler: ZifHandler, 206 | // arg_info: *const ZendInternalArgInfo, 207 | num_args: u32, 208 | flags: u32, 209 | } 210 | 211 | #[repr(C)] 212 | #[derive(Debug)] 213 | pub struct ZendLlistElement { 214 | next: *mut ZendLlistElement, 215 | prev: *mut ZendLlistElement, 216 | data: *mut c_void, 217 | } 218 | 219 | type LlistDtorFunc = extern "C" fn(*mut c_void); 220 | 221 | #[repr(C)] 222 | #[derive(Debug)] 223 | pub struct ZendLlist { 224 | head: *mut ZendLlistElement, 225 | tail: *mut ZendLlistElement, 226 | count: usize, 227 | size: usize, 228 | dtor: LlistDtorFunc, 229 | persistent: c_uchar, 230 | traverse_ptr: *mut ZendLlistElement, 231 | } 232 | 233 | extern "C" { 234 | pub fn zend_signal_startup(); 235 | } 236 | 237 | #[cfg(feature = "zts")] 238 | #[macro_export] 239 | macro_rules! zend_tsrmg_fast { 240 | ($offset: expr, $ty: ty, $element: ident) => { 241 | $crate::tsrm::tsrmg_fast!($offset, $ty, $element) 242 | }; 243 | } 244 | 245 | #[cfg(feature = "zts")] 246 | pub use zend_tsrmg_fast; 247 | -------------------------------------------------------------------------------- /sys/src/zend/stream.rs: -------------------------------------------------------------------------------- 1 | use std::ffi::{c_int, c_void}; 2 | use std::fmt::{Debug, Formatter}; 3 | use std::mem::ManuallyDrop; 4 | use std::os::fd::RawFd; 5 | 6 | use libc::c_char; 7 | 8 | use crate::zend::{ZendString, ZendUchar}; 9 | 10 | pub type ZendStreamFsizer = extern "C" fn(handle: *mut c_void); 11 | pub type ZendStreamReader = extern "C" fn(handle: *mut c_void, buf: *mut c_char, len: usize); 12 | pub type ZendStreamCloser = extern "C" fn(handle: *mut c_void); 13 | 14 | #[repr(C)] 15 | #[derive(Debug)] 16 | pub struct ZendStream { 17 | handle: *mut c_void, 18 | isatty: c_int, 19 | reader: ZendStreamReader, 20 | fsizer: ZendStreamFsizer, 21 | closer: ZendStreamCloser, 22 | } 23 | 24 | #[repr(C)] 25 | pub union ZendFileHandleUnion { 26 | pub fp: RawFd, 27 | pub stream: ManuallyDrop, 28 | } 29 | 30 | impl Debug for ZendFileHandleUnion { 31 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 32 | unsafe { write!(f, "Union(fp: {:?}, stream: {:?})", &self.fp, &self.stream) } 33 | } 34 | } 35 | 36 | #[repr(C)] 37 | #[derive(Debug)] 38 | pub struct ZendFileHandle { 39 | pub handle: ZendFileHandleUnion, 40 | pub filename: *mut ZendString, 41 | pub opened_path: *mut ZendString, 42 | pub ty: ZendUchar, 43 | pub primary_script: bool, 44 | pub in_list: bool, 45 | pub buf: *mut c_char, 46 | pub len: usize, 47 | } 48 | 49 | extern "C" { 50 | pub fn zend_stream_init_fp(handle: *mut ZendFileHandle, fp: RawFd, filename: *const c_char); 51 | pub fn zend_stream_init_filename(handle: *mut ZendFileHandle, filename: *const c_char); 52 | } 53 | -------------------------------------------------------------------------------- /sys/src/zend/string.rs: -------------------------------------------------------------------------------- 1 | use crate::zend::ZendString; 2 | 3 | pub const ZEND_STR_AUTOGLOBAL_SERVER: usize = 66; 4 | 5 | extern "C" { 6 | pub static zend_known_strings: *mut *mut ZendString; 7 | } 8 | 9 | #[macro_export] 10 | macro_rules! zstr_known { 11 | ($idx: expr) => { 12 | ::std::slice::from_raw_parts($crate::zend::string::zend_known_strings, $idx + 1)[$idx] 13 | }; 14 | } 15 | 16 | pub use zstr_known; 17 | --------------------------------------------------------------------------------