ÿØÿà JFIF ÿÛ „ ( %!1"%)+...383-7(-.+
-%%--------+------------/----------------------------ÿÀ ¶" ÿÄ ÿÄ @ !1AQaq‘¡"±ÁÑð2’BRráS‚ñ3b¢CT²Ò #cÿÄ ÿÄ ' 1!AQ2a"‘±#ÿÚ ? ò(/p‘—–¢·,M|¯G»R£üešT. ôŸEoCFñ‡ 4ÔkåóxR|µÁ¨ÓDà!Ç´µ˜‡p ÍQ‹§!þž^õWsŒy åÁ§$á«%ºq˜™JyyË0y«^Ï
-3ÃÏËÈ£Æ\P’ä„s&•‹Üs üô'àWt¹pñCp$bÚF`·7.^)¾!)ÒÙ˜–ÅÏš^h¾ø³·ìe±ŒaeÖ—Í,e=B}Jéߦ$$½—šÙÜCC¯¶è8β–Åkèwx
LÉngT±æ¹£Ócœ¿Í/©Éÿ ‰ÚCÒmq;Tt¶–}0"zÖPcd1š¤tˆ„ÐÓâqú[™öUCŠ2޿دÉ(¸ßúçšmW,Ò ºf‹Ån™ÄLêÃ8üÁkÁ€L¥ÍuJ1œôrÂSŒÓöt!7EUíïb)AËi¬â-ÙHk8òÁiXYwÅ)O^"ÇØriÛô{»wRUKÙÏÚlÓ¬€‚’שT]
ªb—ÊîKC^×M“xùäñz¬zJ×{4[¹M'IÆeH1LCWÕ]œûº WDæà°OÅ‚¹c²ÞuA–rL`HšpCez‡V’— Ž‚Ë„–ñ'µR0ÕÖ=À:±G»C\nÆÉ5*¢ †3šhQ4ýÒi$Õ1"Ü]¢p-q3zcQ$ªö¨¥æf›‘»´ÝÚHá„e²JÇ–iÊ:·à¬Øc5Åk»Laª*wi
[0Ówk ¦a¦0Õ²ÅÅ‚T¸’³q:Æ<¹ú Ò˜Æ}2VE•Ѐp¡Ô3Úº …h³^LJºçì¥Ánó|˜ÖˆÎˆ+«¦dø‘Mº–d\ªDðÛ„Ì×LÝ——Ð9Ç|•FèçVm™¨€™3õS–9Äå¢<̉Ìm¢±`·º˜&Z²ž Ë®D«¶»6™‰©HÈÀá«hi³04æ’hxœi3ï¨(ÓL·†‹¶ËpŒ
ƒÜÒ? :õdsÀ–3æÓ·Üjâ¬9—]8n¼&]I F£¼…ì–—Œ0v°LÇÅfÛ2TÖ’aµ˜N@ÖBSÏ^à´4-±°b×nÈÈœÆD=KdŒø…ÄÈK,›ÖR§fjü$^ÔÎ!„6^ s:Üun\ôkCÞò÷<—Lúl
Í›G¹ÀPá¼Nc¡šÒ…ÙWͳœ±vÊáЄ×9‹P‰cEØ‘™›µŸP<×g1
º©Ø¬wiÁ^l5×I/';Ë+´Z‡ÓÄFÕp[Èð’
HÄ ó
9¬Dl4“é±Ï”V=^Hð;žLädÉa‚°Ë,#/Ž~²BÔÛ
QãñQtIeórVB,ÏÂf‹4#Μc‹É3ZIÖ Œ¢¥·üxa‡Ãçè„jŠ[5 Ä!U?,3žÎ×…ðdÓ÷háŠA‰ìÄ4÷ÃÜZÃE{‰®+W\ZÍE[‰»µk»MÝ`¢©†˜ÃV‹-f¢¡†¢a«eŠ%«Y¨©q%jâd,Ôq`) ¤¦…šˆ ¦E>0Ùb²t–Ÿ
÷jsςҒKÈcø(é›;k(’#ôŒQ
™C>
õ³M9óºÆµ¤çâ;uÀ)5>RÔ¸fÓ~Ȧ—’-$fe«"FâUˆÊwµPÏu
w+"åÉǫ6s™Û9(À¨ù©hE°½†n`m~“@©›p!Vkhµ Á1šbEqqÊ@ºèl›2 –Yã%‘‚hÛ{a¶‡ÅÞM²¬çL34®Çl]®‹ŽØŒm'RÜe35æöˆÁ cP9šeÁköo´L³Ì=p8]”‡B¶,šº|ÉdzXˆØk*ÇÚ{#ñ‰pã(€¶‡9ý'šÜ³½¯kƒ†Â’ëSOƒ•Å®H6+a¢µˆ‹Y¨b˜b+XˆÖ!°u!¢"µˆˆn2ˆ Å0Ä`Å Ô®c(ÓÜGº•Ä»Œ âWî%q.áÐÄ÷î%umÍ£+ÜQ,Vn¦-GphU¸¢X&,Gt
·K¢ÅÅ·¥RÄÊÉbKn
NR2g$VµÕó
Qr#–ÓZUÏð0ÎtÙÀœz
ëöo“Îk¯n„T°"SÞ+³/…€½"ižãO%Í%&Δâ‘ËØ´IˆÓ°Ë‰ÞM3.™yçÁzit›`4C`k¢¼á!álÄï sÂ[×!¤l¾æo"ƒIÔ'@ªu)3›ô®“@Z
à¾]
üœ'‡4¸PÞkÁ-qÄH‰ÓÍBd´ÿ —¹°ÄA&ÊUC„öz‚‚RæŠtf¬>˜ÑidšEçÑL÷áý¡V±h§c¿¥¨ƒ@g¼…Ýö^ÞËc.ž„æ“I[ª+·zÐÒÚ,½Ð»¶€C›7jk$๖€Ž¾ÅÙpp¶ÍþéΤ ½ØÎŒq ñpæžÅ¥#Øâ49ÃÂK^MYV“,¶Éz_òæ:…;Õ«¦I3âJ£¤û5$7Èxün\â]Êe¯(Ÿ&Ž‹¶2<6Ćf× æ¢Æ±qWı[(ÙÂŽç‚T7¨@ÈÉÍß‚ïÙ"&3TYlGކ)†#5ŠA©^T2ÆÁ†)©†©†¤yGXÁ†©"†)©¼ÅV WS†#©]R–r‹q5ÕbâWþBh¯u+ªÅÄ×ü„nÑ^êkªÁj‰jeœWˆÕÕ`µDµ2Ì+Ä µDµµ5Ô{¤Þ0RF’H÷AÛ<ÊÁ§ ƈæ0Ñ£ê4 öÚµ[¬/1²€â<-¬šö²r×0o×w ´xÐÒË„
g01¬„åEM蛇Ã\6µE›‘fÙO k÷CºnÓ1`iîÒ²áÂ!ÑLÄÿ
³¬\õ*:M=Ç»c‹2[‰ØsÕLò\ŒK L^™üÄN\¶#»
Ç\……ßïIœÉ$¸ÎñÍ®ÔHÇ Ûí/´>Li”„†g^$ 7NÍÑÑ2M2ªNg=k½Ð}Ÿl6‡ —JWˆ”ÞéT·+µ¦üÂFè¢Vs6ýÆ4»2+2IÝ9ô9®ÇGÙÇ1+Ä8;*Õ§ž½D*îÑWÚçá3Ma¤·ˆ¥t}š²Ü…Q+Æüµ8HíS”üxGéÁˆ¦Ël„éÈ 5 µÄƒ6äÜ(kIš¯S†fÖ&¸®×v|Äyˆ*禌Éù@7-®Ä[]ÎÖ¿ê`º…=:…žJVnݳvðÖKE¼‚ »mà ÷f®:Ë™–4rð¡4` ܹçž~‹C=œ…¾Ïj|VDtK.ƒ"9 Ï
–éXá³6WÒïIL-Ї
Ç
readme_moodle.txt 0000644 00000000340 15226547251 0010107 0 ustar 00 Instructions to import/update the Slim Framework Moodle:
1. Update any dependencies, including Guzzle
2. Download the latest release from https://github.com/slimphp/Slim
3. Replace the files in slim/* with those in the zip
slim/SECURITY.md 0000644 00000000436 15226547251 0007315 0 ustar 00 # Security Policy
### Supported Versions
| Version | Supported |
| ------- | ------------------ |
| 3.x.x | :white_check_mark: |
| 4.x.x | :white_check_mark: |
### Reporting a Vulnerability
To report a vulnerability please send an email to security@slimframework.com
slim/composer.json 0000644 00000006503 15226547251 0010247 0 ustar 00 {
"name": "slim/slim",
"type": "library",
"description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs",
"keywords": ["framework","micro","api","router"],
"homepage": "https://www.slimframework.com",
"license": "MIT",
"authors": [
{
"name": "Josh Lockhart",
"email": "hello@joshlockhart.com",
"homepage": "https://joshlockhart.com"
},
{
"name": "Andrew Smith",
"email": "a.smith@silentworks.co.uk",
"homepage": "http://silentworks.co.uk"
},
{
"name": "Rob Allen",
"email": "rob@akrabat.com",
"homepage": "http://akrabat.com"
},
{
"name": "Pierre Berube",
"email": "pierre@lgse.com",
"homepage": "http://www.lgse.com"
},
{
"name": "Gabriel Manricks",
"email": "gmanricks@me.com",
"homepage": "http://gabrielmanricks.com"
}
],
"support": {
"docs": "https://www.slimframework.com/docs/v4/",
"forum": "https://discourse.slimframework.com/",
"irc": "irc://irc.freenode.net:6667/slimphp",
"issues": "https://github.com/slimphp/Slim/issues",
"rss": "https://www.slimframework.com/blog/feed.rss",
"slack": "https://slimphp.slack.com/",
"source": "https://github.com/slimphp/Slim",
"wiki": "https://github.com/slimphp/Slim/wiki"
},
"require": {
"php": "^7.4 || ^8.0",
"ext-json": "*",
"nikic/fast-route": "^1.3",
"psr/container": "^1.0 || ^2.0",
"psr/http-factory": "^1.0",
"psr/http-message": "^1.1 || ^2.0",
"psr/http-server-handler": "^1.0",
"psr/http-server-middleware": "^1.0",
"psr/log": "^1.1 || ^2.0 || ^3.0"
},
"require-dev": {
"ext-simplexml": "*",
"adriansuter/php-autoload-override": "^1.4",
"guzzlehttp/psr7": "^2.6",
"httpsoft/http-message": "^1.1",
"httpsoft/http-server-request": "^1.1",
"laminas/laminas-diactoros": "^2.17 || ^3",
"nyholm/psr7": "^1.8",
"nyholm/psr7-server": "^1.1",
"phpspec/prophecy": "^1.19",
"phpspec/prophecy-phpunit": "^2.1",
"phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^9.6",
"slim/http": "^1.3",
"slim/psr7": "^1.6",
"squizlabs/php_codesniffer": "^3.9"
},
"autoload": {
"psr-4": {
"Slim\\": "Slim"
}
},
"autoload-dev": {
"psr-4": {
"Slim\\Tests\\": "tests"
}
},
"scripts": {
"test": [
"@phpunit",
"@phpcs",
"@phpstan"
],
"phpunit": "phpunit",
"phpcs": "phpcs",
"phpstan": "phpstan --memory-limit=-1"
},
"suggest": {
"ext-simplexml": "Needed to support XML format in BodyParsingMiddleware",
"ext-xml": "Needed to support XML format in BodyParsingMiddleware",
"slim/psr7": "Slim PSR-7 implementation. See https://www.slimframework.com/docs/v4/start/installation.html for more information.",
"php-di/php-di": "PHP-DI is the recommended container library to be used with Slim"
},
"config": {
"sort-packages": true
}
}
slim/CHANGELOG.md 0000644 00000050633 15226547251 0007341 0 ustar 00 # Changelog
# 4.11.0 - 2022-11-06
- [3180: Declare types](https://github.com/slimphp/Slim/pull/3180) thanks to @nbayramberdiyev
- [3181: Update laminas/laminas-diactoros requirement from ^2.8 to ^2.9](https://github.com/slimphp/Slim/pull/3181) thanks to @dependabot[bot]
- [3182: Update guzzlehttp/psr7 requirement from ^2.1 to ^2.2](https://github.com/slimphp/Slim/pull/3182) thanks to @dependabot[bot]
- [3183: Update phpstan/phpstan requirement from ^1.4 to ^1.5](https://github.com/slimphp/Slim/pull/3183) thanks to @dependabot[bot]
- [3184: Update adriansuter/php-autoload-override requirement from ^1.2 to ^1.3](https://github.com/slimphp/Slim/pull/3184) thanks to @dependabot[bot]
- [3189: Update phpstan/phpstan requirement from ^1.5 to ^1.6](https://github.com/slimphp/Slim/pull/3189) thanks to @dependabot[bot]
- [3191: Adding property types to Middleware classes](https://github.com/slimphp/Slim/pull/3191) thanks to @ashleycoles
- [3193: Handlers types](https://github.com/slimphp/Slim/pull/3193) thanks to @ashleycoles
- [3194: Adding types to AbstractErrorRenderer](https://github.com/slimphp/Slim/pull/3194) thanks to @ashleycoles
- [3195: Adding prop types for Exception classes](https://github.com/slimphp/Slim/pull/3195) thanks to @ashleycoles
- [3196: Adding property type declarations for Factory classes](https://github.com/slimphp/Slim/pull/3196) thanks to @ashleycoles
- [3197: Remove redundant docblock types](https://github.com/slimphp/Slim/pull/3197) thanks to @theodorejb
- [3199: Update laminas/laminas-diactoros requirement from ^2.9 to ^2.11](https://github.com/slimphp/Slim/pull/3199) thanks to @dependabot[bot]
- [3200: Update phpstan/phpstan requirement from ^1.6 to ^1.7](https://github.com/slimphp/Slim/pull/3200) thanks to @dependabot[bot]
- [3205: Update guzzlehttp/psr7 requirement from ^2.2 to ^2.4](https://github.com/slimphp/Slim/pull/3205) thanks to @dependabot[bot]
- [3206: Update squizlabs/php_codesniffer requirement from ^3.6 to ^3.7](https://github.com/slimphp/Slim/pull/3206) thanks to @dependabot[bot]
- [3207: Update phpstan/phpstan requirement from ^1.7 to ^1.8](https://github.com/slimphp/Slim/pull/3207) thanks to @dependabot[bot]
- [3211: Assign null coalescing to coalesce equal](https://github.com/slimphp/Slim/pull/3211) thanks to @MathiasReker
- [3213: Void return](https://github.com/slimphp/Slim/pull/3213) thanks to @MathiasReker
- [3214: Is null](https://github.com/slimphp/Slim/pull/3214) thanks to @MathiasReker
- [3216: Refactor](https://github.com/slimphp/Slim/pull/3216) thanks to @mehdihasanpour
- [3218: Refactor some code](https://github.com/slimphp/Slim/pull/3218) thanks to @mehdihasanpour
- [3221: Cleanup](https://github.com/slimphp/Slim/pull/3221) thanks to @mehdihasanpour
- [3225: Update laminas/laminas-diactoros requirement from ^2.11 to ^2.14](https://github.com/slimphp/Slim/pull/3225) thanks to @dependabot[bot]
- [3228: Using assertSame to let assert equal be restricted](https://github.com/slimphp/Slim/pull/3228) thanks to @peter279k
- [3229: Update laminas/laminas-diactoros requirement from ^2.14 to ^2.17](https://github.com/slimphp/Slim/pull/3229) thanks to @dependabot[bot]
- [3235: Persist routes indexed by name in RouteCollector for improved performance.](https://github.com/slimphp/Slim/pull/3235) thanks to @BusterNeece
# 4.10.0 - 2022-03-14
- [3120: Add a new PSR-17 factory to Psr17FactoryProvider](https://github.com/slimphp/Slim/pull/3120) thanks to @solventt
- [3123: Replace deprecated setMethods() in tests](https://github.com/slimphp/Slim/pull/3123) thanks to @solventt
- [3126: Update guzzlehttp/psr7 requirement from ^2.0 to ^2.1](https://github.com/slimphp/Slim/pull/3126) thanks to @dependabot[bot]
- [3127: PHPStan v1.0](https://github.com/slimphp/Slim/pull/3127) thanks to @t0mmy742
- [3128: Update phpstan/phpstan requirement from ^1.0 to ^1.2](https://github.com/slimphp/Slim/pull/3128) thanks to @dependabot[bot]
- [3129: Deprecate PHP 7.3](https://github.com/slimphp/Slim/pull/3129) thanks to @l0gicgate
- [3130: Removed double defined PHP 7.4](https://github.com/slimphp/Slim/pull/3130) thanks to @flangofas
- [3132: Add new `RequestResponseNamedArgs` route strategy](https://github.com/slimphp/Slim/pull/3132) thanks to @adoy
- [3133: Improve typehinting for `RouteParserInterface`](https://github.com/slimphp/Slim/pull/3133) thanks to @jerowork
- [3135: Update phpstan/phpstan requirement from ^1.2 to ^1.3](https://github.com/slimphp/Slim/pull/3135) thanks to @dependabot[bot]
- [3137: Update phpspec/prophecy requirement from ^1.14 to ^1.15](https://github.com/slimphp/Slim/pull/3137) thanks to @dependabot[bot]
- [3138: Update license year](https://github.com/slimphp/Slim/pull/3138) thanks to @Awilum
- [3139: Fixed #1730 (reintroduced in 4.x)](https://github.com/slimphp/Slim/pull/3139) thanks to @adoy
- [3145: Update phpstan/phpstan requirement from ^1.3 to ^1.4](https://github.com/slimphp/Slim/pull/3145) thanks to @dependabot[bot]
- [3146: Inherit HttpException from RuntimeException](https://github.com/slimphp/Slim/pull/3146) thanks to @nbayramberdiyev
- [3148: Upgrade to HTML5](https://github.com/slimphp/Slim/pull/3148) thanks to @nbayramberdiyev
- [3172: Update nyholm/psr7 requirement from ^1.4 to ^1.5](https://github.com/slimphp/Slim/pull/3172) thanks to @dependabot[bot]
# 4.9.0 - 2021-10-05
- [3058: Implement exception class for Gone Http error](https://github.com/slimphp/Slim/pull/3058) thanks to @TheKernelPanic
- [3086: Update slim/psr7 requirement from ^1.3 to ^1.4](https://github.com/slimphp/Slim/pull/3086) thanks to @dependabot[bot]
- [3087: Update nyholm/psr7-server requirement from ^1.0.1 to ^1.0.2](https://github.com/slimphp/Slim/pull/3087) thanks to @dependabot[bot]
- [3093: Update phpstan/phpstan requirement from ^0.12.85 to ^0.12.90](https://github.com/slimphp/Slim/pull/3093) thanks to @dependabot[bot]
- [3099: Allow updated psr log](https://github.com/slimphp/Slim/pull/3099) thanks to @t0mmy742
- [3104: Drop php7.2](https://github.com/slimphp/Slim/pull/3104) thanks to @t0mmy742
- [3106: Use PSR-17 factory from Guzzle/psr7 2.0](https://github.com/slimphp/Slim/pull/3106) thanks to @t0mmy742
- [3108: Update README file](https://github.com/slimphp/Slim/pull/3108) thanks to @t0mmy742
- [3112: Update laminas/laminas-diactoros requirement from ^2.6 to ^2.8](https://github.com/slimphp/Slim/pull/3112) thanks to @dependabot[bot]
- [3114: Update slim/psr7 requirement from ^1.4 to ^1.5](https://github.com/slimphp/Slim/pull/3114) thanks to @dependabot[bot]
- [3115: Update phpstan/phpstan requirement from ^0.12.96 to ^0.12.99](https://github.com/slimphp/Slim/pull/3115) thanks to @dependabot[bot]
- [3116: Remove Zend Diactoros references](https://github.com/slimphp/Slim/pull/3116) thanks to @l0gicgate
# 4.8.0 - 2021-05-19
- [3034: Fix phpunit dependency version](https://github.com/slimphp/Slim/pull/3034) thanks to @l0gicgate
- [3037: Replace Travis by GitHub Actions](https://github.com/slimphp/Slim/pull/3037) thanks to @t0mmy742
- [3043: Cover App creation from AppFactory with empty Container](https://github.com/slimphp/Slim/pull/3043) thanks to @t0mmy742
- [3045: Update phpstan/phpstan requirement from ^0.12.58 to ^0.12.64](https://github.com/slimphp/Slim/pull/3045) thanks to @dependabot-preview[bot]
- [3047: documentation: min php 7.2 required](https://github.com/slimphp/Slim/pull/3047) thanks to @Rotzbua
- [3054: Update phpstan/phpstan requirement from ^0.12.64 to ^0.12.70](https://github.com/slimphp/Slim/pull/3054) thanks to @dependabot-preview[bot]
- [3056: Fix docblock in ErrorMiddleware](https://github.com/slimphp/Slim/pull/3056) thanks to @piotr-cz
- [3060: Update phpstan/phpstan requirement from ^0.12.70 to ^0.12.80](https://github.com/slimphp/Slim/pull/3060) thanks to @dependabot-preview[bot]
- [3061: Update nyholm/psr7 requirement from ^1.3 to ^1.4](https://github.com/slimphp/Slim/pull/3061) thanks to @dependabot-preview[bot]
- [3063: Allow ^1.0 || ^2.0 in psr/container](https://github.com/slimphp/Slim/pull/3063) thanks to @Ayesh
- [3069: Classname/Method Callable Arrays](https://github.com/slimphp/Slim/pull/3069) thanks to @ddrv
- [3078: Update squizlabs/php_codesniffer requirement from ^3.5 to ^3.6](https://github.com/slimphp/Slim/pull/3078) thanks to @dependabot[bot]
- [3079: Update phpspec/prophecy requirement from ^1.12 to ^1.13](https://github.com/slimphp/Slim/pull/3079) thanks to @dependabot[bot]
- [3080: Update guzzlehttp/psr7 requirement from ^1.7 to ^1.8](https://github.com/slimphp/Slim/pull/3080) thanks to @dependabot[bot]
- [3082: Update phpstan/phpstan requirement from ^0.12.80 to ^0.12.85](https://github.com/slimphp/Slim/pull/3082) thanks to @dependabot[bot]
# 4.7.0 - 2020-11-30
### Fixed
- [3027: Fix: FastRoute dispatcher and data generator should match](https://github.com/slimphp/Slim/pull/3027) thanks to @edudobay
### Added
- [3015: PHP 8 support](https://github.com/slimphp/Slim/pull/3015) thanks to @edudobay
### Optimizations
- [3024: Randomize tests](https://github.com/slimphp/Slim/pull/3024) thanks to @pawel-slowik
## 4.6.0 - 2020-11-15
### Fixed
- [2942: Fix PHPdoc for error handlers in ErrorMiddleware ](https://github.com/slimphp/Slim/pull/2942) thanks to @TiMESPLiNTER
- [2944: Remove unused function in ErrorHandler](https://github.com/slimphp/Slim/pull/2944) thanks to @l0gicgate
- [2960: Fix phpstan 0.12 errors](https://github.com/slimphp/Slim/pull/2960) thanks to @adriansuter
- [2982: Removing cloning statements in tests](https://github.com/slimphp/Slim/pull/2982) thanks to @l0gicgate
- [3017: Fix request creator factory test](https://github.com/slimphp/Slim/pull/3017) thanks to @pawel-slowik
- [3022: Ensure RouteParser Always Present After Routing](https://github.com/slimphp/Slim/pull/3022) thanks to @l0gicgate
### Added
- [2949: Add the support in composer.json](https://github.com/slimphp/Slim/pull/2949) thanks to @ddrv
- [2958: Strict empty string content type checking in BodyParsingMiddleware::getMediaType](https://github.com/slimphp/Slim/pull/2958) thanks to @Ayesh
- [2997: Add hints to methods](https://github.com/slimphp/Slim/pull/2997) thanks to @evgsavosin - [3000: Fix route controller test](https://github.com/slimphp/Slim/pull/3000) thanks to @pawel-slowik
- [3001: Add missing `$strategy` parameter in a Route test](https://github.com/slimphp/Slim/pull/3001) thanks to @pawel-slowik
### Optimizations
- [2951: Minor optimizations in if() blocks](https://github.com/slimphp/Slim/pull/2951) thanks to @Ayesh
- [2959: Micro optimization: Declare closures in BodyParsingMiddleware as static](https://github.com/slimphp/Slim/pull/2959) thanks to @Ayesh
- [2978: Split the routing results to its own function.](https://github.com/slimphp/Slim/pull/2978) thanks to @dlundgren
### Dependencies Updated
- [2953: Update nyholm/psr7-server requirement from ^0.4.1](https://github.com/slimphp/Slim/pull/2953) thanks to @dependabot-preview[bot]
- [2954: Update laminas/laminas-diactoros requirement from ^2.1 to ^2.3](https://github.com/slimphp/Slim/pull/2954) thanks to @dependabot-preview[bot]
- [2955: Update guzzlehttp/psr7 requirement from ^1.5 to ^1.6](https://github.com/slimphp/Slim/pull/2955) thanks to @dependabot-preview[bot]
- [2956: Update slim/psr7 requirement from ^1.0 to ^1.1](https://github.com/slimphp/Slim/pull/2956) thanks to @dependabot-preview[bot]
- [2957: Update nyholm/psr7 requirement from ^1.1 to ^1.2](https://github.com/slimphp/Slim/pull/2957) thanks to @dependabot-preview[bot]
- [2963: Update phpstan/phpstan requirement from ^0.12.23 to ^0.12.25](https://github.com/slimphp/Slim/pull/2963) thanks to @dependabot-preview[bot]
- [2965: Update adriansuter/php-autoload-override requirement from ^1.0 to ^1.1](https://github.com/slimphp/Slim/pull/2965) thanks to @dependabot-preview[bot]
- [2967: Update nyholm/psr7 requirement from ^1.2 to ^1.3](https://github.com/slimphp/Slim/pull/2967) thanks to @dependabot-preview[bot]
- [2969: Update nyholm/psr7-server requirement from ^0.4.1 to ^1.0.0](https://github.com/slimphp/Slim/pull/2969) thanks to @dependabot-preview[bot]
- [2970: Update phpstan/phpstan requirement from ^0.12.25 to ^0.12.26](https://github.com/slimphp/Slim/pull/2970) thanks to @dependabot-preview[bot]
- [2971: Update phpstan/phpstan requirement from ^0.12.26 to ^0.12.27](https://github.com/slimphp/Slim/pull/2971) thanks to @dependabot-preview[bot]
- [2972: Update phpstan/phpstan requirement from ^0.12.27 to ^0.12.28](https://github.com/slimphp/Slim/pull/2972) thanks to @dependabot-preview[bot]
- [2973: Update phpstan/phpstan requirement from ^0.12.28 to ^0.12.29](https://github.com/slimphp/Slim/pull/2973) thanks to @dependabot-preview[bot]
- [2975: Update phpstan/phpstan requirement from ^0.12.29 to ^0.12.30](https://github.com/slimphp/Slim/pull/2975) thanks to @dependabot-preview[bot]
- [2976: Update phpstan/phpstan requirement from ^0.12.30 to ^0.12.31](https://github.com/slimphp/Slim/pull/2976) thanks to @dependabot-preview[bot]
- [2980: Update phpstan/phpstan requirement from ^0.12.31 to ^0.12.32](https://github.com/slimphp/Slim/pull/2980) thanks to @dependabot-preview[bot]
- [2981: Update phpspec/prophecy requirement from ^1.10 to ^1.11](https://github.com/slimphp/Slim/pull/2981) thanks to @dependabot-preview[bot]
- [2986: Update phpstan/phpstan requirement from ^0.12.32 to ^0.12.33](https://github.com/slimphp/Slim/pull/2986) thanks to @dependabot-preview[bot]
- [2990: Update phpstan/phpstan requirement from ^0.12.33 to ^0.12.34](https://github.com/slimphp/Slim/pull/2990) thanks to @dependabot-preview[bot]
- [2991: Update phpstan/phpstan requirement from ^0.12.34 to ^0.12.35](https://github.com/slimphp/Slim/pull/2991) thanks to @dependabot-preview[bot]
- [2993: Update phpstan/phpstan requirement from ^0.12.35 to ^0.12.36](https://github.com/slimphp/Slim/pull/2993) thanks to @dependabot-preview[bot]
- [2995: Update phpstan/phpstan requirement from ^0.12.36 to ^0.12.37](https://github.com/slimphp/Slim/pull/2995) thanks to @dependabot-preview[bot]
- [3010: Update guzzlehttp/psr7 requirement from ^1.6 to ^1.7](https://github.com/slimphp/Slim/pull/3010) thanks to @dependabot-preview[bot]
- [3011: Update phpspec/prophecy requirement from ^1.11 to ^1.12](https://github.com/slimphp/Slim/pull/3011) thanks to @dependabot-preview[bot]
- [3012: Update slim/http requirement from ^1.0 to ^1.1](https://github.com/slimphp/Slim/pull/3012) thanks to @dependabot-preview[bot]
- [3013: Update slim/psr7 requirement from ^1.1 to ^1.2](https://github.com/slimphp/Slim/pull/3013) thanks to @dependabot-preview[bot]
- [3014: Update laminas/laminas-diactoros requirement from ^2.3 to ^2.4](https://github.com/slimphp/Slim/pull/3014) thanks to @dependabot-preview[bot]
- [3018: Update phpstan/phpstan requirement from ^0.12.37 to ^0.12.54](https://github.com/slimphp/Slim/pull/3018) thanks to @dependabot-preview[bot]
## 4.5.0 - 2020-04-14
### Added
- [2928](https://github.com/slimphp/Slim/pull/2928) Test against PHP 7.4
- [2937](https://github.com/slimphp/Slim/pull/2937) Add support for PSR-3
### Fixed
- [2916](https://github.com/slimphp/Slim/pull/2916) Rename phpcs.xml to phpcs.xml.dist
- [2917](https://github.com/slimphp/Slim/pull/2917) Update .editorconfig
- [2925](https://github.com/slimphp/Slim/pull/2925) ResponseEmitter: Don't remove Content-Type and Content-Length when body is empt
- [2932](https://github.com/slimphp/Slim/pull/2932) Update the Tidelift enterprise language
- [2938](https://github.com/slimphp/Slim/pull/2938) Modify usage of deprecated expectExceptionMessageRegExp() method
## 4.4.0 - 2020-01-04
### Added
- [2862](https://github.com/slimphp/Slim/pull/2862) Optionally handle subclasses of exceptions in custom error handler
- [2869](https://github.com/slimphp/Slim/pull/2869) php-di/php-di added in composer suggestion
- [2874](https://github.com/slimphp/Slim/pull/2874) Add `null` to param type-hints
- [2889](https://github.com/slimphp/Slim/pull/2889) Make `RouteContext` attributes customizable and change default to use private names
- [2907](https://github.com/slimphp/Slim/pull/2907) Migrate to PSR-12 convention
- [2910](https://github.com/slimphp/Slim/pull/2910) Migrate Zend to Laminas
- [2912](https://github.com/slimphp/Slim/pull/2912) Add Laminas PSR17 Factory
- [2913](https://github.com/slimphp/Slim/pull/2913) Update php-autoload-override version
- [2914](https://github.com/slimphp/Slim/pull/2914) Added ability to add handled exceptions as an array
### Fixed
- [2864](https://github.com/slimphp/Slim/pull/2864) Optimize error message in error handling if displayErrorDetails was not set
- [2876](https://github.com/slimphp/Slim/pull/2876) Update links from http to https
- [2877](https://github.com/slimphp/Slim/pull/2877) Fix docblock for `Slim\Routing\RouteCollector::cacheFile`
- [2878](https://github.com/slimphp/Slim/pull/2878) check body is writable only on ouput buffering append
- [2896](https://github.com/slimphp/Slim/pull/2896) Render errors uniformly
- [2902](https://github.com/slimphp/Slim/pull/2902) Fix prophecies
- [2908](https://github.com/slimphp/Slim/pull/2908) Use autoload-dev for `Slim\Tests` namespace
### Removed
- [2871](https://github.com/slimphp/Slim/pull/2871) Remove explicit type-hint
- [2872](https://github.com/slimphp/Slim/pull/2872) Remove type-hint
## 4.3.0 - 2019-10-05
### Added
- [2819](https://github.com/slimphp/Slim/pull/2819) Added description to addRoutingMiddleware()
- [2820](https://github.com/slimphp/Slim/pull/2820) Update link to homepage in composer.json
- [2828](https://github.com/slimphp/Slim/pull/2828) Allow URIs with leading multi-slashes
- [2832](https://github.com/slimphp/Slim/pull/2832) Refactor `FastRouteDispatcher`
- [2835](https://github.com/slimphp/Slim/pull/2835) Rename `pathFor` to `urlFor` in docblock
- [2846](https://github.com/slimphp/Slim/pull/2846) Correcting the branch name as per issue-2843
- [2849](https://github.com/slimphp/Slim/pull/2849) Create class alias for FastRoute\RouteCollector
- [2855](https://github.com/slimphp/Slim/pull/2855) Add list of allowed methods to HttpMethodNotAllowedException
- [2860](https://github.com/slimphp/Slim/pull/2860) Add base path to `$request` and use `RouteContext` to read
### Fixed
- [2839](https://github.com/slimphp/Slim/pull/2839) Fix description for handler signature in phpdocs
- [2844](https://github.com/slimphp/Slim/pull/2844) Handle base path by routeCollector instead of RouteCollectorProxy
- [2845](https://github.com/slimphp/Slim/pull/2845) Fix composer scripts
- [2851](https://github.com/slimphp/Slim/pull/2851) Fix example of 'Hello World' app
- [2854](https://github.com/slimphp/Slim/pull/2854) Fix undefined property in tests
### Removed
- [2853](https://github.com/slimphp/Slim/pull/2853) Remove unused classes
## 4.2.0 - 2019-08-20
### Added
- [2787](https://github.com/slimphp/Slim/pull/2787) Add an advanced callable resolver
- [2791](https://github.com/slimphp/Slim/pull/2791) Add `inferPrivatePropertyTypeFromConstructor` to phpstan
- [2793](https://github.com/slimphp/Slim/pull/2793) Add ability to configure application via a container in `AppFactory`
- [2798](https://github.com/slimphp/Slim/pull/2798) Add PSR-7 Agnostic Body Parsing Middleware
- [2801](https://github.com/slimphp/Slim/pull/2801) Add `setLogErrorRenderer()` method to `ErrorHandler`
- [2807](https://github.com/slimphp/Slim/pull/2807) Add check for Slim callable notation if no resolver given
- [2803](https://github.com/slimphp/Slim/pull/2803) Add ability to emit non seekable streams in `ResponseEmitter`
- [2817](https://github.com/slimphp/Slim/pull/2817) Add the ability to pass in a custom `MiddlewareDispatcherInterface` to the `App`
### Fixed
- [2789](https://github.com/slimphp/Slim/pull/2789) Fix Cookie header detection in `ResponseEmitter`
- [2796](https://github.com/slimphp/Slim/pull/2796) Fix http message format
- [2800](https://github.com/slimphp/Slim/pull/2800) Fix null comparisons more clear in `ErrorHandler`
- [2802](https://github.com/slimphp/Slim/pull/2802) Fix incorrect search of a header in stack
- [2806](https://github.com/slimphp/Slim/pull/2806) Simplify `Route::prepare()` method argument preparation
- [2809](https://github.com/slimphp/Slim/pull/2809) Eliminate a duplicate code via HOF in `MiddlewareDispatcher`
- [2816](https://github.com/slimphp/Slim/pull/2816) Fix RouteCollectorProxy::redirect() bug
### Removed
- [2811](https://github.com/slimphp/Slim/pull/2811) Remove `DeferredCallable`
## 4.1.0 - 2019-08-06
### Added
- [#2779](https://github.com/slimphp/Slim/pull/2774) Add support for Slim callables `Class:method` resolution & Container Closure auto-binding in `MiddlewareDispatcher`
- [#2774](https://github.com/slimphp/Slim/pull/2774) Add possibility for custom `RequestHandler` invocation strategies
### Fixed
- [#2776](https://github.com/slimphp/Slim/pull/2774) Fix group middleware on multiple nested groups
slim/LICENSE.md 0000644 00000002046 15226547251 0007127 0 ustar 00 Copyright (c) 2011-2022 Josh Lockhart
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
slim/Slim/Factory/AppFactory.php 0000644 00000016535 15226547251 0012627 0 ustar 00 has(ResponseFactoryInterface::class)
&& (
$responseFactoryFromContainer = $container->get(ResponseFactoryInterface::class)
) instanceof ResponseFactoryInterface
? $responseFactoryFromContainer
: self::determineResponseFactory();
$callableResolver = $container->has(CallableResolverInterface::class)
&& (
$callableResolverFromContainer = $container->get(CallableResolverInterface::class)
) instanceof CallableResolverInterface
? $callableResolverFromContainer
: null;
$routeCollector = $container->has(RouteCollectorInterface::class)
&& (
$routeCollectorFromContainer = $container->get(RouteCollectorInterface::class)
) instanceof RouteCollectorInterface
? $routeCollectorFromContainer
: null;
$routeResolver = $container->has(RouteResolverInterface::class)
&& (
$routeResolverFromContainer = $container->get(RouteResolverInterface::class)
) instanceof RouteResolverInterface
? $routeResolverFromContainer
: null;
$middlewareDispatcher = $container->has(MiddlewareDispatcherInterface::class)
&& (
$middlewareDispatcherFromContainer = $container->get(MiddlewareDispatcherInterface::class)
) instanceof MiddlewareDispatcherInterface
? $middlewareDispatcherFromContainer
: null;
return new App(
$responseFactory,
$container,
$callableResolver,
$routeCollector,
$routeResolver,
$middlewareDispatcher
);
}
/**
* @throws RuntimeException
*/
public static function determineResponseFactory(): ResponseFactoryInterface
{
if (static::$responseFactory) {
if (static::$streamFactory) {
return static::attemptResponseFactoryDecoration(static::$responseFactory, static::$streamFactory);
}
return static::$responseFactory;
}
$psr17FactoryProvider = static::$psr17FactoryProvider ?? new Psr17FactoryProvider();
/** @var Psr17Factory $psr17factory */
foreach ($psr17FactoryProvider->getFactories() as $psr17factory) {
if ($psr17factory::isResponseFactoryAvailable()) {
$responseFactory = $psr17factory::getResponseFactory();
if (static::$streamFactory || $psr17factory::isStreamFactoryAvailable()) {
$streamFactory = static::$streamFactory ?? $psr17factory::getStreamFactory();
return static::attemptResponseFactoryDecoration($responseFactory, $streamFactory);
}
return $responseFactory;
}
}
throw new RuntimeException(
"Could not detect any PSR-17 ResponseFactory implementations. " .
"Please install a supported implementation in order to use `AppFactory::create()`. " .
"See https://github.com/slimphp/Slim/blob/4.x/README.md for a list of supported implementations."
);
}
protected static function attemptResponseFactoryDecoration(
ResponseFactoryInterface $responseFactory,
StreamFactoryInterface $streamFactory
): ResponseFactoryInterface {
if (
static::$slimHttpDecoratorsAutomaticDetectionEnabled
&& SlimHttpPsr17Factory::isResponseFactoryAvailable()
) {
return SlimHttpPsr17Factory::createDecoratedResponseFactory($responseFactory, $streamFactory);
}
return $responseFactory;
}
public static function setPsr17FactoryProvider(Psr17FactoryProviderInterface $psr17FactoryProvider): void
{
static::$psr17FactoryProvider = $psr17FactoryProvider;
}
public static function setResponseFactory(ResponseFactoryInterface $responseFactory): void
{
static::$responseFactory = $responseFactory;
}
public static function setStreamFactory(StreamFactoryInterface $streamFactory): void
{
static::$streamFactory = $streamFactory;
}
public static function setContainer(ContainerInterface $container): void
{
static::$container = $container;
}
public static function setCallableResolver(CallableResolverInterface $callableResolver): void
{
static::$callableResolver = $callableResolver;
}
public static function setRouteCollector(RouteCollectorInterface $routeCollector): void
{
static::$routeCollector = $routeCollector;
}
public static function setRouteResolver(RouteResolverInterface $routeResolver): void
{
static::$routeResolver = $routeResolver;
}
public static function setMiddlewareDispatcher(MiddlewareDispatcherInterface $middlewareDispatcher): void
{
static::$middlewareDispatcher = $middlewareDispatcher;
}
public static function setSlimHttpDecoratorsAutomaticDetection(bool $enabled): void
{
static::$slimHttpDecoratorsAutomaticDetectionEnabled = $enabled;
}
}
slim/Slim/Factory/Psr17/Psr17Factory.php 0000644 00000005354 15226547251 0013734 0 ustar 00 serverRequestCreator = $serverRequestCreator;
$this->serverRequestCreatorMethod = $serverRequestCreatorMethod;
}
/**
* {@inheritdoc}
*/
public function createServerRequestFromGlobals(): ServerRequestInterface
{
/** @var callable $callable */
$callable = [$this->serverRequestCreator, $this->serverRequestCreatorMethod];
return (Closure::fromCallable($callable))();
}
}
slim/Slim/Factory/Psr17/SlimHttpPsr17Factory.php 0000644 00000002170 15226547251 0015412 0 ustar 00 serverRequestCreator = $serverRequestCreator;
}
/**
* {@inheritdoc}
*/
public function createServerRequestFromGlobals(): ServerRequestInterface
{
if (!static::isServerRequestDecoratorAvailable()) {
throw new RuntimeException('The Slim-Http ServerRequest decorator is not available.');
}
$request = $this->serverRequestCreator->createServerRequestFromGlobals();
if (
!((
$decoratedServerRequest = new static::$serverRequestDecoratorClass($request)
) instanceof ServerRequestInterface)
) {
throw new RuntimeException(get_called_class() . ' could not instantiate a decorated server request.');
}
return $decoratedServerRequest;
}
public static function isServerRequestDecoratorAvailable(): bool
{
return class_exists(static::$serverRequestDecoratorClass);
}
}
slim/Slim/Factory/Psr17/SlimPsr17Factory.php 0000644 00000001130 15226547251 0014545 0 ustar 00 getFactories() as $psr17Factory) {
if ($psr17Factory::isServerRequestCreatorAvailable()) {
$serverRequestCreator = $psr17Factory::getServerRequestCreator();
return static::attemptServerRequestCreatorDecoration($serverRequestCreator);
}
}
throw new RuntimeException(
"Could not detect any ServerRequest creator implementations. " .
"Please install a supported implementation in order to use `App::run()` " .
"without having to pass in a `ServerRequest` object. " .
"See https://github.com/slimphp/Slim/blob/4.x/README.md for a list of supported implementations."
);
}
protected static function attemptServerRequestCreatorDecoration(
ServerRequestCreatorInterface $serverRequestCreator
): ServerRequestCreatorInterface {
if (
static::$slimHttpDecoratorsAutomaticDetectionEnabled
&& SlimHttpServerRequestCreator::isServerRequestDecoratorAvailable()
) {
return new SlimHttpServerRequestCreator($serverRequestCreator);
}
return $serverRequestCreator;
}
public static function setPsr17FactoryProvider(Psr17FactoryProviderInterface $psr17FactoryProvider): void
{
static::$psr17FactoryProvider = $psr17FactoryProvider;
}
public static function setServerRequestCreator(ServerRequestCreatorInterface $serverRequestCreator): void
{
self::$serverRequestCreator = $serverRequestCreator;
}
public static function setSlimHttpDecoratorsAutomaticDetection(bool $enabled): void
{
static::$slimHttpDecoratorsAutomaticDetectionEnabled = $enabled;
}
}
slim/Slim/App.php 0000644 00000015157 15226547251 0007667 0 ustar 00 routeResolver = $routeResolver ?? new RouteResolver($this->routeCollector);
$routeRunner = new RouteRunner($this->routeResolver, $this->routeCollector->getRouteParser(), $this);
if (!$middlewareDispatcher) {
$middlewareDispatcher = new MiddlewareDispatcher($routeRunner, $this->callableResolver, $container);
} else {
$middlewareDispatcher->seedMiddlewareStack($routeRunner);
}
$this->middlewareDispatcher = $middlewareDispatcher;
}
/**
* @return RouteResolverInterface
*/
public function getRouteResolver(): RouteResolverInterface
{
return $this->routeResolver;
}
/**
* @return MiddlewareDispatcherInterface
*/
public function getMiddlewareDispatcher(): MiddlewareDispatcherInterface
{
return $this->middlewareDispatcher;
}
/**
* @param MiddlewareInterface|string|callable $middleware
*/
public function add($middleware): self
{
$this->middlewareDispatcher->add($middleware);
return $this;
}
/**
* @param MiddlewareInterface $middleware
*/
public function addMiddleware(MiddlewareInterface $middleware): self
{
$this->middlewareDispatcher->addMiddleware($middleware);
return $this;
}
/**
* Add the Slim built-in routing middleware to the app middleware stack
*
* This method can be used to control middleware order and is not required for default routing operation.
*
* @return RoutingMiddleware
*/
public function addRoutingMiddleware(): RoutingMiddleware
{
$routingMiddleware = new RoutingMiddleware(
$this->getRouteResolver(),
$this->getRouteCollector()->getRouteParser()
);
$this->add($routingMiddleware);
return $routingMiddleware;
}
/**
* Add the Slim built-in error middleware to the app middleware stack
*
* @param bool $displayErrorDetails
* @param bool $logErrors
* @param bool $logErrorDetails
* @param LoggerInterface|null $logger
*
* @return ErrorMiddleware
*/
public function addErrorMiddleware(
bool $displayErrorDetails,
bool $logErrors,
bool $logErrorDetails,
?LoggerInterface $logger = null
): ErrorMiddleware {
$errorMiddleware = new ErrorMiddleware(
$this->getCallableResolver(),
$this->getResponseFactory(),
$displayErrorDetails,
$logErrors,
$logErrorDetails,
$logger
);
$this->add($errorMiddleware);
return $errorMiddleware;
}
/**
* Add the Slim body parsing middleware to the app middleware stack
*
* @param callable[] $bodyParsers
*
* @return BodyParsingMiddleware
*/
public function addBodyParsingMiddleware(array $bodyParsers = []): BodyParsingMiddleware
{
$bodyParsingMiddleware = new BodyParsingMiddleware($bodyParsers);
$this->add($bodyParsingMiddleware);
return $bodyParsingMiddleware;
}
/**
* Run application
*
* This method traverses the application middleware stack and then sends the
* resultant Response object to the HTTP client.
*
* @param ServerRequestInterface|null $request
* @return void
*/
public function run(?ServerRequestInterface $request = null): void
{
if (!$request) {
$serverRequestCreator = ServerRequestCreatorFactory::create();
$request = $serverRequestCreator->createServerRequestFromGlobals();
}
$response = $this->handle($request);
$responseEmitter = new ResponseEmitter();
$responseEmitter->emit($response);
}
/**
* Handle a request
*
* This method traverses the application middleware stack and then returns the
* resultant Response object.
*
* @param ServerRequestInterface $request
* @return ResponseInterface
*/
public function handle(ServerRequestInterface $request): ResponseInterface
{
$response = $this->middlewareDispatcher->handle($request);
/**
* This is to be in compliance with RFC 2616, Section 9.
* If the incoming request method is HEAD, we need to ensure that the response body
* is empty as the request may fall back on a GET route handler due to FastRoute's
* routing logic which could potentially append content to the response body
* https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.4
*/
$method = strtoupper($request->getMethod());
if ($method === 'HEAD') {
$emptyBody = $this->responseFactory->createResponse()->getBody();
return $response->withBody($emptyBody);
}
return $response;
}
}
slim/Slim/Handlers/Strategies/RequestResponseArgs.php 0000644 00000001733 15226547251 0017000 0 ustar 00 $routeArguments
*/
public function __invoke(
callable $callable,
ServerRequestInterface $request,
ResponseInterface $response,
array $routeArguments
): ResponseInterface {
return $callable($request, $response, ...array_values($routeArguments));
}
}
slim/Slim/Handlers/Strategies/RequestResponseNamedArgs.php 0000644 00000002212 15226547251 0017736 0 ustar 00 = 8.0.0');
}
}
/**
* Invoke a route callable with request, response and all route parameters
* as individual arguments.
*
* @param array $routeArguments
*/
public function __invoke(
callable $callable,
ServerRequestInterface $request,
ResponseInterface $response,
array $routeArguments
): ResponseInterface {
return $callable($request, $response, ...$routeArguments);
}
}
slim/Slim/Handlers/Strategies/RequestResponse.php 0000644 00000002050 15226547251 0016154 0 ustar 00 $routeArguments
*/
public function __invoke(
callable $callable,
ServerRequestInterface $request,
ResponseInterface $response,
array $routeArguments
): ResponseInterface {
foreach ($routeArguments as $k => $v) {
$request = $request->withAttribute($k, $v);
}
return $callable($request, $response, $routeArguments);
}
}
slim/Slim/Handlers/Strategies/RequestHandler.php 0000644 00000002460 15226547251 0015740 0 ustar 00 appendRouteArgumentsToRequestAttributes = $appendRouteArgumentsToRequestAttributes;
}
/**
* Invoke a route callable that implements RequestHandlerInterface
*
* @param array $routeArguments
*/
public function __invoke(
callable $callable,
ServerRequestInterface $request,
ResponseInterface $response,
array $routeArguments
): ResponseInterface {
if ($this->appendRouteArgumentsToRequestAttributes) {
foreach ($routeArguments as $k => $v) {
$request = $request->withAttribute($k, $v);
}
}
return $callable($request);
}
}
slim/Slim/Handlers/ErrorHandler.php 0000644 00000023111 15226547251 0013263 0 ustar 00
*/
protected array $errorRenderers = [
'application/json' => JsonErrorRenderer::class,
'application/xml' => XmlErrorRenderer::class,
'text/xml' => XmlErrorRenderer::class,
'text/html' => HtmlErrorRenderer::class,
'text/plain' => PlainTextErrorRenderer::class,
];
protected bool $displayErrorDetails = false;
protected bool $logErrors;
protected bool $logErrorDetails = false;
protected ?string $contentType = null;
protected ?string $method = null;
protected ServerRequestInterface $request;
protected Throwable $exception;
protected int $statusCode;
protected CallableResolverInterface $callableResolver;
protected ResponseFactoryInterface $responseFactory;
protected LoggerInterface $logger;
public function __construct(
CallableResolverInterface $callableResolver,
ResponseFactoryInterface $responseFactory,
?LoggerInterface $logger = null
) {
$this->callableResolver = $callableResolver;
$this->responseFactory = $responseFactory;
$this->logger = $logger ?: $this->getDefaultLogger();
}
/**
* Invoke error handler
*
* @param ServerRequestInterface $request The most recent Request object
* @param Throwable $exception The caught Exception object
* @param bool $displayErrorDetails Whether or not to display the error details
* @param bool $logErrors Whether or not to log errors
* @param bool $logErrorDetails Whether or not to log error details
*/
public function __invoke(
ServerRequestInterface $request,
Throwable $exception,
bool $displayErrorDetails,
bool $logErrors,
bool $logErrorDetails
): ResponseInterface {
$this->displayErrorDetails = $displayErrorDetails;
$this->logErrors = $logErrors;
$this->logErrorDetails = $logErrorDetails;
$this->request = $request;
$this->exception = $exception;
$this->method = $request->getMethod();
$this->statusCode = $this->determineStatusCode();
if ($this->contentType === null) {
$this->contentType = $this->determineContentType($request);
}
if ($logErrors) {
$this->writeToErrorLog();
}
return $this->respond();
}
/**
* Force the content type for all error handler responses.
*
* @param string|null $contentType The content type
*/
public function forceContentType(?string $contentType): void
{
$this->contentType = $contentType;
}
protected function determineStatusCode(): int
{
if ($this->method === 'OPTIONS') {
return 200;
}
if ($this->exception instanceof HttpException) {
return $this->exception->getCode();
}
return 500;
}
/**
* Determine which content type we know about is wanted using Accept header
*
* Note: This method is a bare-bones implementation designed specifically for
* Slim's error handling requirements. Consider a fully-feature solution such
* as willdurand/negotiation for any other situation.
*/
protected function determineContentType(ServerRequestInterface $request): ?string
{
$acceptHeader = $request->getHeaderLine('Accept');
$selectedContentTypes = array_intersect(
explode(',', $acceptHeader),
array_keys($this->errorRenderers)
);
$count = count($selectedContentTypes);
if ($count) {
$current = current($selectedContentTypes);
/**
* Ensure other supported content types take precedence over text/plain
* when multiple content types are provided via Accept header.
*/
if ($current === 'text/plain' && $count > 1) {
$next = next($selectedContentTypes);
if (is_string($next)) {
return $next;
}
}
if (is_string($current)) {
return $current;
}
}
if (preg_match('/\+(json|xml)/', $acceptHeader, $matches)) {
$mediaType = 'application/' . $matches[1];
if (array_key_exists($mediaType, $this->errorRenderers)) {
return $mediaType;
}
}
return null;
}
/**
* Determine which renderer to use based on content type
*
* @throws RuntimeException
*/
protected function determineRenderer(): callable
{
if ($this->contentType !== null && array_key_exists($this->contentType, $this->errorRenderers)) {
$renderer = $this->errorRenderers[$this->contentType];
} else {
$renderer = $this->defaultErrorRenderer;
}
return $this->callableResolver->resolve($renderer);
}
/**
* Register an error renderer for a specific content-type
*
* @param string $contentType The content-type this renderer should be registered to
* @param ErrorRendererInterface|string|callable $errorRenderer The error renderer
*/
public function registerErrorRenderer(string $contentType, $errorRenderer): void
{
$this->errorRenderers[$contentType] = $errorRenderer;
}
/**
* Set the default error renderer
*
* @param string $contentType The content type of the default error renderer
* @param ErrorRendererInterface|string|callable $errorRenderer The default error renderer
*/
public function setDefaultErrorRenderer(string $contentType, $errorRenderer): void
{
$this->defaultErrorRendererContentType = $contentType;
$this->defaultErrorRenderer = $errorRenderer;
}
/**
* Set the renderer for the error logger
*
* @param ErrorRendererInterface|string|callable $logErrorRenderer
*/
public function setLogErrorRenderer($logErrorRenderer): void
{
$this->logErrorRenderer = $logErrorRenderer;
}
/**
* Write to the error log if $logErrors has been set to true
*/
protected function writeToErrorLog(): void
{
$renderer = $this->callableResolver->resolve($this->logErrorRenderer);
$error = $renderer($this->exception, $this->logErrorDetails);
if (!$this->displayErrorDetails) {
$error .= "\nTips: To display error details in HTTP response ";
$error .= 'set "displayErrorDetails" to true in the ErrorHandler constructor.';
}
$this->logError($error);
}
/**
* Wraps the error_log function so that this can be easily tested
*/
protected function logError(string $error): void
{
$this->logger->error($error);
}
/**
* Returns a default logger implementation.
*/
protected function getDefaultLogger(): LoggerInterface
{
return new Logger();
}
protected function respond(): ResponseInterface
{
$response = $this->responseFactory->createResponse($this->statusCode);
if ($this->contentType !== null && array_key_exists($this->contentType, $this->errorRenderers)) {
$response = $response->withHeader('Content-type', $this->contentType);
} else {
$response = $response->withHeader('Content-type', $this->defaultErrorRendererContentType);
}
if ($this->exception instanceof HttpMethodNotAllowedException) {
$allowedMethods = implode(', ', $this->exception->getAllowedMethods());
$response = $response->withHeader('Allow', $allowedMethods);
}
$renderer = $this->determineRenderer();
$body = call_user_func($renderer, $this->exception, $this->displayErrorDetails);
if ($body !== false) {
/** @var string $body */
$response->getBody()->write($body);
}
return $response;
}
}
slim/Slim/Logger.php 0000644 00000001175 15226547251 0010361 0 ustar 00 $context
*
* @throws InvalidArgumentException
*/
public function log($level, $message, array $context = []): void
{
error_log((string) $message);
}
}
slim/Slim/ResponseEmitter.php 0000644 00000006771 15226547251 0012301 0 ustar 00 responseChunkSize = $responseChunkSize;
}
/**
* Send the response the client
*/
public function emit(ResponseInterface $response): void
{
$isEmpty = $this->isResponseEmpty($response);
if (headers_sent() === false) {
$this->emitHeaders($response);
// Set the status _after_ the headers, because of PHP's "helpful" behavior with location headers.
// See https://github.com/slimphp/Slim/issues/1730
$this->emitStatusLine($response);
}
if (!$isEmpty) {
$this->emitBody($response);
}
}
/**
* Emit Response Headers
*/
private function emitHeaders(ResponseInterface $response): void
{
foreach ($response->getHeaders() as $name => $values) {
$first = strtolower($name) !== 'set-cookie';
foreach ($values as $value) {
$header = sprintf('%s: %s', $name, $value);
header($header, $first);
$first = false;
}
}
}
/**
* Emit Status Line
*/
private function emitStatusLine(ResponseInterface $response): void
{
$statusLine = sprintf(
'HTTP/%s %s %s',
$response->getProtocolVersion(),
$response->getStatusCode(),
$response->getReasonPhrase()
);
header($statusLine, true, $response->getStatusCode());
}
/**
* Emit Body
*/
private function emitBody(ResponseInterface $response): void
{
$body = $response->getBody();
if ($body->isSeekable()) {
$body->rewind();
}
$amountToRead = (int) $response->getHeaderLine('Content-Length');
if (!$amountToRead) {
$amountToRead = $body->getSize();
}
if ($amountToRead) {
while ($amountToRead > 0 && !$body->eof()) {
$length = min($this->responseChunkSize, $amountToRead);
$data = $body->read($length);
echo $data;
$amountToRead -= strlen($data);
if (connection_status() !== CONNECTION_NORMAL) {
break;
}
}
} else {
while (!$body->eof()) {
echo $body->read($this->responseChunkSize);
if (connection_status() !== CONNECTION_NORMAL) {
break;
}
}
}
}
/**
* Asserts response body is empty or status code is 204, 205 or 304
*/
public function isResponseEmpty(ResponseInterface $response): bool
{
if (in_array($response->getStatusCode(), [204, 205, 304], true)) {
return true;
}
$stream = $response->getBody();
$seekable = $stream->isSeekable();
if ($seekable) {
$stream->rewind();
}
return $seekable ? $stream->read(1) === '' : $stream->eof();
}
}
slim/Slim/Error/Renderers/JsonErrorRenderer.php 0000644 00000002642 15226547251 0015576 0 ustar 00 $this->getErrorTitle($exception)];
if ($displayErrorDetails) {
$error['exception'] = [];
do {
$error['exception'][] = $this->formatExceptionFragment($exception);
} while ($exception = $exception->getPrevious());
}
return (string) json_encode($error, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
}
/**
* @return array
*/
private function formatExceptionFragment(Throwable $exception): array
{
/** @var int|string $code */
$code = $exception->getCode();
return [
'type' => get_class($exception),
'code' => $code,
'message' => $exception->getMessage(),
'file' => $exception->getFile(),
'line' => $exception->getLine(),
];
}
}
slim/Slim/Error/Renderers/XmlErrorRenderer.php 0000644 00000003200 15226547251 0015414 0 ustar 00 \n";
$xml .= "\n " . $this->createCdataSection($this->getErrorTitle($exception)) . "\n";
if ($displayErrorDetails) {
do {
$xml .= " \n";
$xml .= ' ' . get_class($exception) . "\n";
$xml .= ' ' . $exception->getCode() . "\n";
$xml .= ' ' . $this->createCdataSection($exception->getMessage()) . "\n";
$xml .= ' ' . $exception->getFile() . "\n";
$xml .= ' ' . $exception->getLine() . "\n";
$xml .= " \n";
} while ($exception = $exception->getPrevious());
}
$xml .= '';
return $xml;
}
/**
* Returns a CDATA section with the given content.
*/
private function createCdataSection(string $content): string
{
return sprintf('', str_replace(']]>', ']]]]>', $content));
}
}
slim/Slim/Error/Renderers/HtmlErrorRenderer.php 0000644 00000005322 15226547251 0015567 0 ustar 00 The application could not run because of the following error:
';
$html .= 'Details
';
$html .= $this->renderExceptionFragment($exception);
} else {
$html = "{$this->getErrorDescription($exception)}
";
}
return $this->renderHtmlBody($this->getErrorTitle($exception), $html);
}
private function renderExceptionFragment(Throwable $exception): string
{
$html = sprintf('Type: %s
', get_class($exception));
/** @var int|string $code */
$code = $exception->getCode();
$html .= sprintf('Code: %s
', $code);
$html .= sprintf('Message: %s
', htmlentities($exception->getMessage()));
$html .= sprintf('File: %s
', $exception->getFile());
$html .= sprintf('Line: %s
', $exception->getLine());
$html .= 'Trace
';
$html .= sprintf('%s
', htmlentities($exception->getTraceAsString()));
return $html;
}
public function renderHtmlBody(string $title = '', string $html = ''): string
{
return sprintf(
'' .
'' .
' ' .
' ' .
' ' .
' %s' .
' ' .
' ' .
' ' .
' %s
' .
' %s
' .
' Go Back' .
' ' .
'',
$title,
$title,
$html
);
}
}
slim/Slim/Error/Renderers/PlainTextErrorRenderer.php 0000644 00000002756 15226547251 0016603 0 ustar 00 getErrorTitle($exception)}\n";
if ($displayErrorDetails) {
$text .= $this->formatExceptionFragment($exception);
while ($exception = $exception->getPrevious()) {
$text .= "\nPrevious Error:\n";
$text .= $this->formatExceptionFragment($exception);
}
}
return $text;
}
private function formatExceptionFragment(Throwable $exception): string
{
$text = sprintf("Type: %s\n", get_class($exception));
$code = $exception->getCode();
/** @var int|string $code */
$text .= sprintf("Code: %s\n", $code);
$text .= sprintf("Message: %s\n", htmlentities($exception->getMessage()));
$text .= sprintf("File: %s\n", $exception->getFile());
$text .= sprintf("Line: %s\n", $exception->getLine());
$text .= sprintf('Trace: %s', $exception->getTraceAsString());
return $text;
}
}
slim/Slim/Error/AbstractErrorRenderer.php 0000644 00000002260 15226547251 0014473 0 ustar 00 getTitle();
}
return $this->defaultErrorTitle;
}
protected function getErrorDescription(Throwable $exception): string
{
if ($exception instanceof HttpException) {
return $exception->getDescription();
}
return $this->defaultErrorDescription;
}
}
slim/Slim/Middleware/RoutingMiddleware.php 0000644 00000006321 15226547251 0014642 0 ustar 00 routeResolver = $routeResolver;
$this->routeParser = $routeParser;
}
/**
* @throws HttpNotFoundException
* @throws HttpMethodNotAllowedException
* @throws RuntimeException
*/
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
$request = $this->performRouting($request);
return $handler->handle($request);
}
/**
* Perform routing
*
* @param ServerRequestInterface $request PSR7 Server Request
*
* @throws HttpNotFoundException
* @throws HttpMethodNotAllowedException
* @throws RuntimeException
*/
public function performRouting(ServerRequestInterface $request): ServerRequestInterface
{
$request = $request->withAttribute(RouteContext::ROUTE_PARSER, $this->routeParser);
$routingResults = $this->resolveRoutingResultsFromRequest($request);
$routeStatus = $routingResults->getRouteStatus();
$request = $request->withAttribute(RouteContext::ROUTING_RESULTS, $routingResults);
switch ($routeStatus) {
case RoutingResults::FOUND:
$routeArguments = $routingResults->getRouteArguments();
$routeIdentifier = $routingResults->getRouteIdentifier() ?? '';
$route = $this->routeResolver
->resolveRoute($routeIdentifier)
->prepare($routeArguments);
return $request->withAttribute(RouteContext::ROUTE, $route);
case RoutingResults::NOT_FOUND:
throw new HttpNotFoundException($request);
case RoutingResults::METHOD_NOT_ALLOWED:
$exception = new HttpMethodNotAllowedException($request);
$exception->setAllowedMethods($routingResults->getAllowedMethods());
throw $exception;
default:
throw new RuntimeException('An unexpected error occurred while performing routing.');
}
}
/**
* Resolves the route from the given request
*/
protected function resolveRoutingResultsFromRequest(ServerRequestInterface $request): RoutingResults
{
return $this->routeResolver->computeRoutingResults(
$request->getUri()->getPath(),
$request->getMethod()
);
}
}
slim/Slim/Middleware/BodyParsingMiddleware.php 0000644 00000013324 15226547251 0015435 0 ustar 00 callable
*/
public function __construct(array $bodyParsers = [])
{
$this->registerDefaultBodyParsers();
foreach ($bodyParsers as $mediaType => $parser) {
$this->registerBodyParser($mediaType, $parser);
}
}
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
$parsedBody = $request->getParsedBody();
if (empty($parsedBody)) {
$parsedBody = $this->parseBody($request);
$request = $request->withParsedBody($parsedBody);
}
return $handler->handle($request);
}
/**
* @param string $mediaType A HTTP media type (excluding content-type params).
* @param callable $callable A callable that returns parsed contents for media type.
*/
public function registerBodyParser(string $mediaType, callable $callable): self
{
$this->bodyParsers[$mediaType] = $callable;
return $this;
}
/**
* @param string $mediaType A HTTP media type (excluding content-type params).
*/
public function hasBodyParser(string $mediaType): bool
{
return isset($this->bodyParsers[$mediaType]);
}
/**
* @param string $mediaType A HTTP media type (excluding content-type params).
* @throws RuntimeException
*/
public function getBodyParser(string $mediaType): callable
{
if (!isset($this->bodyParsers[$mediaType])) {
throw new RuntimeException('No parser for type ' . $mediaType);
}
return $this->bodyParsers[$mediaType];
}
protected function registerDefaultBodyParsers(): void
{
$this->registerBodyParser('application/json', static function ($input) {
$result = json_decode($input, true);
if (!is_array($result)) {
return null;
}
return $result;
});
$this->registerBodyParser('application/x-www-form-urlencoded', static function ($input) {
parse_str($input, $data);
return $data;
});
$xmlCallable = static function ($input) {
$backup = self::disableXmlEntityLoader(true);
$backup_errors = libxml_use_internal_errors(true);
$result = simplexml_load_string($input);
self::disableXmlEntityLoader($backup);
libxml_clear_errors();
libxml_use_internal_errors($backup_errors);
if ($result === false) {
return null;
}
return $result;
};
$this->registerBodyParser('application/xml', $xmlCallable);
$this->registerBodyParser('text/xml', $xmlCallable);
}
/**
* @return null|array|object
*/
protected function parseBody(ServerRequestInterface $request)
{
$mediaType = $this->getMediaType($request);
if ($mediaType === null) {
return null;
}
// Check if this specific media type has a parser registered first
if (!isset($this->bodyParsers[$mediaType])) {
// If not, look for a media type with a structured syntax suffix (RFC 6839)
$parts = explode('+', $mediaType);
if (count($parts) >= 2) {
$mediaType = 'application/' . $parts[count($parts) - 1];
}
}
if (isset($this->bodyParsers[$mediaType])) {
$body = (string)$request->getBody();
$parsed = $this->bodyParsers[$mediaType]($body);
if ($parsed !== null && !is_object($parsed) && !is_array($parsed)) {
throw new RuntimeException(
'Request body media type parser return value must be an array, an object, or null'
);
}
return $parsed;
}
return null;
}
/**
* @return string|null The serverRequest media type, minus content-type params
*/
protected function getMediaType(ServerRequestInterface $request): ?string
{
$contentType = $request->getHeader('Content-Type')[0] ?? null;
if (is_string($contentType) && trim($contentType) !== '') {
$contentTypeParts = explode(';', $contentType);
return strtolower(trim($contentTypeParts[0]));
}
return null;
}
protected static function disableXmlEntityLoader(bool $disable): bool
{
if (LIBXML_VERSION >= 20900) {
// libxml >= 2.9.0 disables entity loading by default, so it is
// safe to skip the real call (deprecated in PHP 8).
return true;
}
// @codeCoverageIgnoreStart
return libxml_disable_entity_loader($disable);
// @codeCoverageIgnoreEnd
}
}
slim/Slim/Middleware/MethodOverrideMiddleware.php 0000644 00000002253 15226547251 0016133 0 ustar 00 getHeaderLine('X-Http-Method-Override');
if ($methodHeader) {
$request = $request->withMethod($methodHeader);
} elseif (strtoupper($request->getMethod()) === 'POST') {
$body = $request->getParsedBody();
if (is_array($body) && !empty($body['_METHOD'])) {
$request = $request->withMethod($body['_METHOD']);
}
if ($request->getBody()->eof()) {
$request->getBody()->rewind();
}
}
return $handler->handle($request);
}
}
slim/Slim/Middleware/OutputBufferingMiddleware.php 0000644 00000004053 15226547251 0016343 0 ustar 00 streamFactory = $streamFactory;
$this->style = $style;
if (!in_array($style, [static::APPEND, static::PREPEND], true)) {
throw new InvalidArgumentException("Invalid style `{$style}`. Must be `append` or `prepend`");
}
}
/**
* @throws Throwable
*/
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
try {
ob_start();
$response = $handler->handle($request);
$output = ob_get_clean();
} catch (Throwable $e) {
ob_end_clean();
throw $e;
}
if (!empty($output)) {
if ($this->style === static::PREPEND) {
$body = $this->streamFactory->createStream();
$body->write($output . $response->getBody());
$response = $response->withBody($body);
} elseif ($this->style === static::APPEND && $response->getBody()->isWritable()) {
$response->getBody()->write($output);
}
}
return $response;
}
}
slim/Slim/Middleware/ErrorMiddleware.php 0000644 00000014666 15226547251 0014317 0 ustar 00 callableResolver = $callableResolver;
$this->responseFactory = $responseFactory;
$this->displayErrorDetails = $displayErrorDetails;
$this->logErrors = $logErrors;
$this->logErrorDetails = $logErrorDetails;
$this->logger = $logger;
}
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
try {
return $handler->handle($request);
} catch (Throwable $e) {
return $this->handleException($request, $e);
}
}
public function handleException(ServerRequestInterface $request, Throwable $exception): ResponseInterface
{
if ($exception instanceof HttpException) {
$request = $exception->getRequest();
}
$exceptionType = get_class($exception);
$handler = $this->getErrorHandler($exceptionType);
return $handler($request, $exception, $this->displayErrorDetails, $this->logErrors, $this->logErrorDetails);
}
/**
* Get callable to handle scenarios where an error
* occurs when processing the current request.
*
* @param string $type Exception/Throwable name. ie: RuntimeException::class
* @return callable|ErrorHandler
*/
public function getErrorHandler(string $type)
{
if (isset($this->handlers[$type])) {
return $this->callableResolver->resolve($this->handlers[$type]);
}
if (isset($this->subClassHandlers[$type])) {
return $this->callableResolver->resolve($this->subClassHandlers[$type]);
}
foreach ($this->subClassHandlers as $class => $handler) {
if (is_subclass_of($type, $class)) {
return $this->callableResolver->resolve($handler);
}
}
return $this->getDefaultErrorHandler();
}
/**
* Get default error handler
*
* @return ErrorHandler|callable
*/
public function getDefaultErrorHandler()
{
if ($this->defaultErrorHandler === null) {
$this->defaultErrorHandler = new ErrorHandler(
$this->callableResolver,
$this->responseFactory,
$this->logger
);
}
return $this->callableResolver->resolve($this->defaultErrorHandler);
}
/**
* Set callable as the default Slim application error handler.
*
* The callable signature MUST match the ErrorHandlerInterface
*
* @see \Slim\Interfaces\ErrorHandlerInterface
*
* 1. Instance of \Psr\Http\Message\ServerRequestInterface
* 2. Instance of \Throwable
* 3. Boolean $displayErrorDetails
* 4. Boolean $logErrors
* 5. Boolean $logErrorDetails
*
* The callable MUST return an instance of
* \Psr\Http\Message\ResponseInterface.
*
* @param string|callable|ErrorHandler $handler
*/
public function setDefaultErrorHandler($handler): self
{
$this->defaultErrorHandler = $handler;
return $this;
}
/**
* Set callable to handle scenarios where an error
* occurs when processing the current request.
*
* The callable signature MUST match the ErrorHandlerInterface
*
* Pass true to $handleSubclasses to make the handler handle all subclasses of
* the type as well. Pass an array of classes to make the same function handle multiple exceptions.
*
* @see \Slim\Interfaces\ErrorHandlerInterface
*
* 1. Instance of \Psr\Http\Message\ServerRequestInterface
* 2. Instance of \Throwable
* 3. Boolean $displayErrorDetails
* 4. Boolean $logErrors
* 5. Boolean $logErrorDetails
*
* The callable MUST return an instance of
* \Psr\Http\Message\ResponseInterface.
*
* @param string|string[] $typeOrTypes Exception/Throwable name.
* ie: RuntimeException::class or an array of classes
* ie: [HttpNotFoundException::class, HttpMethodNotAllowedException::class]
* @param string|callable|ErrorHandlerInterface $handler
*/
public function setErrorHandler($typeOrTypes, $handler, bool $handleSubclasses = false): self
{
if (is_array($typeOrTypes)) {
foreach ($typeOrTypes as $type) {
$this->addErrorHandler($type, $handler, $handleSubclasses);
}
} else {
$this->addErrorHandler($typeOrTypes, $handler, $handleSubclasses);
}
return $this;
}
/**
* Used internally to avoid code repetition when passing multiple exceptions to setErrorHandler().
* @param string|callable|ErrorHandlerInterface $handler
*/
private function addErrorHandler(string $type, $handler, bool $handleSubclasses): void
{
if ($handleSubclasses) {
$this->subClassHandlers[$type] = $handler;
} else {
$this->handlers[$type] = $handler;
}
}
}
slim/Slim/Middleware/ContentLengthMiddleware.php 0000644 00000001613 15226547251 0015766 0 ustar 00 handle($request);
// Add Content-Length header if not already added
$size = $response->getBody()->getSize();
if ($size !== null && !$response->hasHeader('Content-Length')) {
$response = $response->withHeader('Content-Length', (string) $size);
}
return $response;
}
}
slim/Slim/Routing/RouteContext.php 0000644 00000004556 15226547251 0013242 0 ustar 00 getAttribute(self::ROUTE);
$routeParser = $serverRequest->getAttribute(self::ROUTE_PARSER);
$routingResults = $serverRequest->getAttribute(self::ROUTING_RESULTS);
$basePath = $serverRequest->getAttribute(self::BASE_PATH);
if ($routeParser === null || $routingResults === null) {
throw new RuntimeException('Cannot create RouteContext before routing has been completed');
}
/** @var RouteInterface|null $route */
/** @var RouteParserInterface $routeParser */
/** @var RoutingResults $routingResults */
/** @var string|null $basePath */
return new self($route, $routeParser, $routingResults, $basePath);
}
private ?RouteInterface $route;
private RouteParserInterface $routeParser;
private RoutingResults $routingResults;
private ?string $basePath;
private function __construct(
?RouteInterface $route,
RouteParserInterface $routeParser,
RoutingResults $routingResults,
?string $basePath = null
) {
$this->route = $route;
$this->routeParser = $routeParser;
$this->routingResults = $routingResults;
$this->basePath = $basePath;
}
public function getRoute(): ?RouteInterface
{
return $this->route;
}
public function getRouteParser(): RouteParserInterface
{
return $this->routeParser;
}
public function getRoutingResults(): RoutingResults
{
return $this->routingResults;
}
public function getBasePath(): string
{
if ($this->basePath === null) {
throw new RuntimeException('No base path defined.');
}
return $this->basePath;
}
}
slim/Slim/Routing/RouteGroup.php 0000644 00000004737 15226547251 0012713 0 ustar 00 pattern = $pattern;
$this->callable = $callable;
$this->callableResolver = $callableResolver;
$this->routeCollectorProxy = $routeCollectorProxy;
}
/**
* {@inheritdoc}
*/
public function collectRoutes(): RouteGroupInterface
{
if ($this->callableResolver instanceof AdvancedCallableResolverInterface) {
$callable = $this->callableResolver->resolveRoute($this->callable);
} else {
$callable = $this->callableResolver->resolve($this->callable);
}
$callable($this->routeCollectorProxy);
return $this;
}
/**
* {@inheritdoc}
*/
public function add($middleware): RouteGroupInterface
{
$this->middleware[] = $middleware;
return $this;
}
/**
* {@inheritdoc}
*/
public function addMiddleware(MiddlewareInterface $middleware): RouteGroupInterface
{
$this->middleware[] = $middleware;
return $this;
}
/**
* {@inheritdoc}
*/
public function appendMiddlewareToDispatcher(MiddlewareDispatcher $dispatcher): RouteGroupInterface
{
foreach ($this->middleware as $middleware) {
$dispatcher->add($middleware);
}
return $this;
}
/**
* {@inheritdoc}
*/
public function getPattern(): string
{
return $this->pattern;
}
}
slim/Slim/Routing/RouteCollectorProxy.php 0000644 00000011026 15226547251 0014574 0 ustar 00 responseFactory = $responseFactory;
$this->callableResolver = $callableResolver;
$this->container = $container;
$this->routeCollector = $routeCollector ?? new RouteCollector($responseFactory, $callableResolver, $container);
$this->groupPattern = $groupPattern;
}
/**
* {@inheritdoc}
*/
public function getResponseFactory(): ResponseFactoryInterface
{
return $this->responseFactory;
}
/**
* {@inheritdoc}
*/
public function getCallableResolver(): CallableResolverInterface
{
return $this->callableResolver;
}
/**
* {@inheritdoc}
*/
public function getContainer(): ?ContainerInterface
{
return $this->container;
}
/**
* {@inheritdoc}
*/
public function getRouteCollector(): RouteCollectorInterface
{
return $this->routeCollector;
}
/**
* {@inheritdoc}
*/
public function getBasePath(): string
{
return $this->routeCollector->getBasePath();
}
/**
* {@inheritdoc}
*/
public function setBasePath(string $basePath): RouteCollectorProxyInterface
{
$this->routeCollector->setBasePath($basePath);
return $this;
}
/**
* {@inheritdoc}
*/
public function get(string $pattern, $callable): RouteInterface
{
return $this->map(['GET'], $pattern, $callable);
}
/**
* {@inheritdoc}
*/
public function post(string $pattern, $callable): RouteInterface
{
return $this->map(['POST'], $pattern, $callable);
}
/**
* {@inheritdoc}
*/
public function put(string $pattern, $callable): RouteInterface
{
return $this->map(['PUT'], $pattern, $callable);
}
/**
* {@inheritdoc}
*/
public function patch(string $pattern, $callable): RouteInterface
{
return $this->map(['PATCH'], $pattern, $callable);
}
/**
* {@inheritdoc}
*/
public function delete(string $pattern, $callable): RouteInterface
{
return $this->map(['DELETE'], $pattern, $callable);
}
/**
* {@inheritdoc}
*/
public function options(string $pattern, $callable): RouteInterface
{
return $this->map(['OPTIONS'], $pattern, $callable);
}
/**
* {@inheritdoc}
*/
public function any(string $pattern, $callable): RouteInterface
{
return $this->map(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'], $pattern, $callable);
}
/**
* {@inheritdoc}
*/
public function map(array $methods, string $pattern, $callable): RouteInterface
{
$pattern = $this->groupPattern . $pattern;
return $this->routeCollector->map($methods, $pattern, $callable);
}
/**
* {@inheritdoc}
*/
public function group(string $pattern, $callable): RouteGroupInterface
{
$pattern = $this->groupPattern . $pattern;
return $this->routeCollector->group($pattern, $callable);
}
/**
* {@inheritdoc}
*/
public function redirect(string $from, $to, int $status = 302): RouteInterface
{
$responseFactory = $this->responseFactory;
$handler = function () use ($to, $status, $responseFactory) {
$response = $responseFactory->createResponse($status);
return $response->withHeader('Location', (string) $to);
};
return $this->get($from, $handler);
}
}
slim/Slim/Routing/Route.php 0000644 00000021503 15226547251 0011664 0 ustar 00
*/
protected array $arguments = [];
/**
* Route arguments parameters
*
* @var string[]
*/
protected array $savedArguments = [];
/**
* Container
*/
protected ?ContainerInterface $container = null;
protected MiddlewareDispatcher $middlewareDispatcher;
/**
* Route callable
*
* @var callable|string
*/
protected $callable;
protected CallableResolverInterface $callableResolver;
protected ResponseFactoryInterface $responseFactory;
/**
* Route pattern
*/
protected string $pattern;
protected bool $groupMiddlewareAppended = false;
/**
* @param string[] $methods The route HTTP methods
* @param string $pattern The route pattern
* @param callable|string $callable The route callable
* @param ResponseFactoryInterface $responseFactory
* @param CallableResolverInterface $callableResolver
* @param ContainerInterface|null $container
* @param InvocationStrategyInterface|null $invocationStrategy
* @param RouteGroupInterface[] $groups The parent route groups
* @param int $identifier The route identifier
*/
public function __construct(
array $methods,
string $pattern,
$callable,
ResponseFactoryInterface $responseFactory,
CallableResolverInterface $callableResolver,
?ContainerInterface $container = null,
?InvocationStrategyInterface $invocationStrategy = null,
array $groups = [],
int $identifier = 0
) {
$this->methods = $methods;
$this->pattern = $pattern;
$this->callable = $callable;
$this->responseFactory = $responseFactory;
$this->callableResolver = $callableResolver;
$this->container = $container;
$this->invocationStrategy = $invocationStrategy ?? new RequestResponse();
$this->groups = $groups;
$this->identifier = 'route' . $identifier;
$this->middlewareDispatcher = new MiddlewareDispatcher($this, $callableResolver, $container);
}
public function getCallableResolver(): CallableResolverInterface
{
return $this->callableResolver;
}
/**
* {@inheritdoc}
*/
public function getInvocationStrategy(): InvocationStrategyInterface
{
return $this->invocationStrategy;
}
/**
* {@inheritdoc}
*/
public function setInvocationStrategy(InvocationStrategyInterface $invocationStrategy): RouteInterface
{
$this->invocationStrategy = $invocationStrategy;
return $this;
}
/**
* {@inheritdoc}
*/
public function getMethods(): array
{
return $this->methods;
}
/**
* {@inheritdoc}
*/
public function getPattern(): string
{
return $this->pattern;
}
/**
* {@inheritdoc}
*/
public function setPattern(string $pattern): RouteInterface
{
$this->pattern = $pattern;
return $this;
}
/**
* {@inheritdoc}
*/
public function getCallable()
{
return $this->callable;
}
/**
* {@inheritdoc}
*/
public function setCallable($callable): RouteInterface
{
$this->callable = $callable;
return $this;
}
/**
* {@inheritdoc}
*/
public function getName(): ?string
{
return $this->name;
}
/**
* {@inheritdoc}
*/
public function setName(string $name): RouteInterface
{
$this->name = $name;
return $this;
}
/**
* {@inheritdoc}
*/
public function getIdentifier(): string
{
return $this->identifier;
}
/**
* {@inheritdoc}
*/
public function getArgument(string $name, ?string $default = null): ?string
{
if (array_key_exists($name, $this->arguments)) {
return $this->arguments[$name];
}
return $default;
}
/**
* {@inheritdoc}
*/
public function getArguments(): array
{
return $this->arguments;
}
/**
* {@inheritdoc}
*/
public function setArguments(array $arguments, bool $includeInSavedArguments = true): RouteInterface
{
if ($includeInSavedArguments) {
$this->savedArguments = $arguments;
}
$this->arguments = $arguments;
return $this;
}
/**
* @return RouteGroupInterface[]
*/
public function getGroups(): array
{
return $this->groups;
}
/**
* {@inheritdoc}
*/
public function add($middleware): RouteInterface
{
$this->middlewareDispatcher->add($middleware);
return $this;
}
/**
* {@inheritdoc}
*/
public function addMiddleware(MiddlewareInterface $middleware): RouteInterface
{
$this->middlewareDispatcher->addMiddleware($middleware);
return $this;
}
/**
* {@inheritdoc}
*/
public function prepare(array $arguments): RouteInterface
{
$this->arguments = array_replace($this->savedArguments, $arguments);
return $this;
}
/**
* {@inheritdoc}
*/
public function setArgument(string $name, string $value, bool $includeInSavedArguments = true): RouteInterface
{
if ($includeInSavedArguments) {
$this->savedArguments[$name] = $value;
}
$this->arguments[$name] = $value;
return $this;
}
/**
* {@inheritdoc}
*/
public function run(ServerRequestInterface $request): ResponseInterface
{
if (!$this->groupMiddlewareAppended) {
$this->appendGroupMiddlewareToRoute();
}
return $this->middlewareDispatcher->handle($request);
}
/**
* @return void
*/
protected function appendGroupMiddlewareToRoute(): void
{
$inner = $this->middlewareDispatcher;
$this->middlewareDispatcher = new MiddlewareDispatcher($inner, $this->callableResolver, $this->container);
/** @var RouteGroupInterface $group */
foreach (array_reverse($this->groups) as $group) {
$group->appendMiddlewareToDispatcher($this->middlewareDispatcher);
}
$this->groupMiddlewareAppended = true;
}
/**
* {@inheritdoc}
*/
public function handle(ServerRequestInterface $request): ResponseInterface
{
if ($this->callableResolver instanceof AdvancedCallableResolverInterface) {
$callable = $this->callableResolver->resolveRoute($this->callable);
} else {
$callable = $this->callableResolver->resolve($this->callable);
}
$strategy = $this->invocationStrategy;
/** @var string[] $strategyImplements */
$strategyImplements = class_implements($strategy);
if (
is_array($callable)
&& $callable[0] instanceof RequestHandlerInterface
&& !in_array(RequestHandlerInvocationStrategyInterface::class, $strategyImplements)
) {
$strategy = new RequestHandler();
}
$response = $this->responseFactory->createResponse();
return $strategy($callable, $request, $response, $this->arguments);
}
}
slim/Slim/Routing/FastRouteDispatcher.php 0000644 00000006153 15226547251 0014515 0 ustar 00 }
*/
public function dispatch($httpMethod, $uri): array
{
$routingResults = $this->routingResults($httpMethod, $uri);
if ($routingResults[0] === self::FOUND) {
return $routingResults;
}
// For HEAD requests, attempt fallback to GET
if ($httpMethod === 'HEAD') {
$routingResults = $this->routingResults('GET', $uri);
if ($routingResults[0] === self::FOUND) {
return $routingResults;
}
}
// If nothing else matches, try fallback routes
$routingResults = $this->routingResults('*', $uri);
if ($routingResults[0] === self::FOUND) {
return $routingResults;
}
if (!empty($this->getAllowedMethods($uri))) {
return [self::METHOD_NOT_ALLOWED, null, []];
}
return [self::NOT_FOUND, null, []];
}
/**
* @param string $httpMethod
* @param string $uri
*
* @return array{int, string|null, array}
*/
private function routingResults(string $httpMethod, string $uri): array
{
if (isset($this->staticRouteMap[$httpMethod][$uri])) {
/** @var string $routeIdentifier */
$routeIdentifier = $this->staticRouteMap[$httpMethod][$uri];
return [self::FOUND, $routeIdentifier, []];
}
if (isset($this->variableRouteData[$httpMethod])) {
/** @var array{0: int, 1?: string, 2?: array} $result */
$result = $this->dispatchVariableRoute($this->variableRouteData[$httpMethod], $uri);
if ($result[0] === self::FOUND) {
/** @var array{int, string, array} $result */
return [self::FOUND, $result[1], $result[2]];
}
}
return [self::NOT_FOUND, null, []];
}
/**
* @param string $uri
*
* @return string[]
*/
public function getAllowedMethods(string $uri): array
{
if (isset($this->allowedMethods[$uri])) {
return $this->allowedMethods[$uri];
}
$allowedMethods = [];
foreach ($this->staticRouteMap as $method => $uriMap) {
if (isset($uriMap[$uri])) {
$allowedMethods[$method] = true;
}
}
foreach ($this->variableRouteData as $method => $routeData) {
$result = $this->dispatchVariableRoute($routeData, $uri);
if ($result[0] === self::FOUND) {
$allowedMethods[$method] = true;
}
}
return $this->allowedMethods[$uri] = array_keys($allowedMethods);
}
}
slim/Slim/Routing/RouteRunner.php 0000644 00000004537 15226547251 0013066 0 ustar 00 routeResolver = $routeResolver;
$this->routeParser = $routeParser;
$this->routeCollectorProxy = $routeCollectorProxy;
}
/**
* This request handler is instantiated automatically in App::__construct()
* It is at the very tip of the middleware queue meaning it will be executed
* last and it detects whether or not routing has been performed in the user
* defined middleware stack. In the event that the user did not perform routing
* it is done here
*
* @throws HttpNotFoundException
* @throws HttpMethodNotAllowedException
*/
public function handle(ServerRequestInterface $request): ResponseInterface
{
// If routing hasn't been done, then do it now so we can dispatch
if ($request->getAttribute(RouteContext::ROUTING_RESULTS) === null) {
$routingMiddleware = new RoutingMiddleware($this->routeResolver, $this->routeParser);
$request = $routingMiddleware->performRouting($request);
}
if ($this->routeCollectorProxy !== null) {
$request = $request->withAttribute(
RouteContext::BASE_PATH,
$this->routeCollectorProxy->getBasePath()
);
}
/** @var Route $route */
$route = $request->getAttribute(RouteContext::ROUTE);
return $route->run($request);
}
}
slim/Slim/Routing/RoutingResults.php 0000644 00000004513 15226547251 0013601 0 ustar 00
*/
protected array $routeArguments;
/**
* @param array $routeArguments
*/
public function __construct(
DispatcherInterface $dispatcher,
string $method,
string $uri,
int $routeStatus,
?string $routeIdentifier = null,
array $routeArguments = []
) {
$this->dispatcher = $dispatcher;
$this->method = $method;
$this->uri = $uri;
$this->routeStatus = $routeStatus;
$this->routeIdentifier = $routeIdentifier;
$this->routeArguments = $routeArguments;
}
public function getDispatcher(): DispatcherInterface
{
return $this->dispatcher;
}
public function getMethod(): string
{
return $this->method;
}
public function getUri(): string
{
return $this->uri;
}
public function getRouteStatus(): int
{
return $this->routeStatus;
}
public function getRouteIdentifier(): ?string
{
return $this->routeIdentifier;
}
/**
* @return array
*/
public function getRouteArguments(bool $urlDecode = true): array
{
if (!$urlDecode) {
return $this->routeArguments;
}
$routeArguments = [];
foreach ($this->routeArguments as $key => $value) {
$routeArguments[$key] = rawurldecode($value);
}
return $routeArguments;
}
/**
* @return string[]
*/
public function getAllowedMethods(): array
{
return $this->dispatcher->getAllowedMethods($this->uri);
}
}
slim/Slim/Routing/RouteResolver.php 0000644 00000002750 15226547251 0013411 0 ustar 00 routeCollector = $routeCollector;
$this->dispatcher = $dispatcher ?? new Dispatcher($routeCollector);
}
/**
* @param string $uri Should be $request->getUri()->getPath()
*/
public function computeRoutingResults(string $uri, string $method): RoutingResults
{
$uri = rawurldecode($uri);
if ($uri === '' || $uri[0] !== '/') {
$uri = '/' . $uri;
}
return $this->dispatcher->dispatch($method, $uri);
}
/**
* @throws RuntimeException
*/
public function resolveRoute(string $identifier): RouteInterface
{
return $this->routeCollector->lookupRoute($identifier);
}
}
slim/Slim/Routing/Dispatcher.php 0000644 00000004650 15226547251 0012660 0 ustar 00 routeCollector = $routeCollector;
}
protected function createDispatcher(): FastRouteDispatcher
{
if ($this->dispatcher) {
return $this->dispatcher;
}
$routeDefinitionCallback = function (FastRouteCollector $r): void {
$basePath = $this->routeCollector->getBasePath();
foreach ($this->routeCollector->getRoutes() as $route) {
$r->addRoute($route->getMethods(), $basePath . $route->getPattern(), $route->getIdentifier());
}
};
$cacheFile = $this->routeCollector->getCacheFile();
if ($cacheFile) {
/** @var FastRouteDispatcher $dispatcher */
$dispatcher = \FastRoute\cachedDispatcher($routeDefinitionCallback, [
'dataGenerator' => GroupCountBased::class,
'dispatcher' => FastRouteDispatcher::class,
'routeParser' => new Std(),
'cacheFile' => $cacheFile,
]);
} else {
/** @var FastRouteDispatcher $dispatcher */
$dispatcher = \FastRoute\simpleDispatcher($routeDefinitionCallback, [
'dataGenerator' => GroupCountBased::class,
'dispatcher' => FastRouteDispatcher::class,
'routeParser' => new Std(),
]);
}
$this->dispatcher = $dispatcher;
return $this->dispatcher;
}
/**
* {@inheritdoc}
*/
public function dispatch(string $method, string $uri): RoutingResults
{
$dispatcher = $this->createDispatcher();
$results = $dispatcher->dispatch($method, $uri);
return new RoutingResults($this, $method, $uri, $results[0], $results[1], $results[2]);
}
/**
* {@inheritdoc}
*/
public function getAllowedMethods(string $uri): array
{
$dispatcher = $this->createDispatcher();
return $dispatcher->getAllowedMethods($uri);
}
}
slim/Slim/Routing/RouteParser.php 0000644 00000007502 15226547251 0013044 0 ustar 00 routeCollector = $routeCollector;
$this->routeParser = new Std();
}
/**
* {@inheritdoc}
*/
public function relativeUrlFor(string $routeName, array $data = [], array $queryParams = []): string
{
$route = $this->routeCollector->getNamedRoute($routeName);
$pattern = $route->getPattern();
$segments = [];
$segmentName = '';
/*
* $routes is an associative array of expressions representing a route as multiple segments
* There is an expression for each optional parameter plus one without the optional parameters
* The most specific is last, hence why we reverse the array before iterating over it
*/
$expressions = array_reverse($this->routeParser->parse($pattern));
foreach ($expressions as $expression) {
foreach ($expression as $segment) {
/*
* Each $segment is either a string or an array of strings
* containing optional parameters of an expression
*/
if (is_string($segment)) {
$segments[] = $segment;
continue;
}
/** @var string[] $segment */
/*
* If we don't have a data element for this segment in the provided $data
* we cancel testing to move onto the next expression with a less specific item
*/
if (!array_key_exists($segment[0], $data)) {
$segments = [];
$segmentName = $segment[0];
break;
}
$segments[] = $data[$segment[0]];
}
/*
* If we get to this logic block we have found all the parameters
* for the provided $data which means we don't need to continue testing
* less specific expressions
*/
if (!empty($segments)) {
break;
}
}
if (empty($segments)) {
throw new InvalidArgumentException('Missing data for URL segment: ' . $segmentName);
}
$url = implode('', $segments);
if ($queryParams) {
$url .= '?' . http_build_query($queryParams);
}
return $url;
}
/**
* {@inheritdoc}
*/
public function urlFor(string $routeName, array $data = [], array $queryParams = []): string
{
$basePath = $this->routeCollector->getBasePath();
$url = $this->relativeUrlFor($routeName, $data, $queryParams);
if ($basePath) {
$url = $basePath . $url;
}
return $url;
}
/**
* {@inheritdoc}
*/
public function fullUrlFor(UriInterface $uri, string $routeName, array $data = [], array $queryParams = []): string
{
$path = $this->urlFor($routeName, $data, $queryParams);
$scheme = $uri->getScheme();
$authority = $uri->getAuthority();
$protocol = ($scheme ? $scheme . ':' : '') . ($authority ? '//' . $authority : '');
return $protocol . $path;
}
}
slim/Slim/Routing/RouteCollector.php 0000644 00000016737 15226547251 0013550 0 ustar 00 responseFactory = $responseFactory;
$this->callableResolver = $callableResolver;
$this->container = $container;
$this->defaultInvocationStrategy = $defaultInvocationStrategy ?? new RequestResponse();
$this->routeParser = $routeParser ?? new RouteParser($this);
if ($cacheFile) {
$this->setCacheFile($cacheFile);
}
}
public function getRouteParser(): RouteParserInterface
{
return $this->routeParser;
}
/**
* Get default route invocation strategy
*/
public function getDefaultInvocationStrategy(): InvocationStrategyInterface
{
return $this->defaultInvocationStrategy;
}
public function setDefaultInvocationStrategy(InvocationStrategyInterface $strategy): RouteCollectorInterface
{
$this->defaultInvocationStrategy = $strategy;
return $this;
}
/**
* {@inheritdoc}
*/
public function getCacheFile(): ?string
{
return $this->cacheFile;
}
/**
* {@inheritdoc}
*/
public function setCacheFile(string $cacheFile): RouteCollectorInterface
{
if (file_exists($cacheFile) && !is_readable($cacheFile)) {
throw new RuntimeException(
sprintf('Route collector cache file `%s` is not readable', $cacheFile)
);
}
if (!file_exists($cacheFile) && !is_writable(dirname($cacheFile))) {
throw new RuntimeException(
sprintf('Route collector cache file directory `%s` is not writable', dirname($cacheFile))
);
}
$this->cacheFile = $cacheFile;
return $this;
}
/**
* {@inheritdoc}
*/
public function getBasePath(): string
{
return $this->basePath;
}
/**
* Set the base path used in urlFor()
*/
public function setBasePath(string $basePath): RouteCollectorInterface
{
$this->basePath = $basePath;
return $this;
}
/**
* {@inheritdoc}
*/
public function getRoutes(): array
{
return $this->routes;
}
/**
* {@inheritdoc}
*/
public function removeNamedRoute(string $name): RouteCollectorInterface
{
$route = $this->getNamedRoute($name);
unset($this->routesByName[$route->getName()], $this->routes[$route->getIdentifier()]);
return $this;
}
/**
* {@inheritdoc}
*/
public function getNamedRoute(string $name): RouteInterface
{
if (isset($this->routesByName[$name])) {
$route = $this->routesByName[$name];
if ($route->getName() === $name) {
return $route;
}
unset($this->routesByName[$name]);
}
foreach ($this->routes as $route) {
if ($name === $route->getName()) {
$this->routesByName[$name] = $route;
return $route;
}
}
throw new RuntimeException('Named route does not exist for name: ' . $name);
}
/**
* {@inheritdoc}
*/
public function lookupRoute(string $identifier): RouteInterface
{
if (!isset($this->routes[$identifier])) {
throw new RuntimeException('Route not found, looks like your route cache is stale.');
}
return $this->routes[$identifier];
}
/**
* {@inheritdoc}
*/
public function group(string $pattern, $callable): RouteGroupInterface
{
$routeGroup = $this->createGroup($pattern, $callable);
$this->routeGroups[] = $routeGroup;
$routeGroup->collectRoutes();
array_pop($this->routeGroups);
return $routeGroup;
}
/**
* @param string|callable $callable
*/
protected function createGroup(string $pattern, $callable): RouteGroupInterface
{
$routeCollectorProxy = $this->createProxy($pattern);
return new RouteGroup($pattern, $callable, $this->callableResolver, $routeCollectorProxy);
}
protected function createProxy(string $pattern): RouteCollectorProxyInterface
{
return new RouteCollectorProxy(
$this->responseFactory,
$this->callableResolver,
$this->container,
$this,
$pattern
);
}
/**
* {@inheritdoc}
*/
public function map(array $methods, string $pattern, $handler): RouteInterface
{
$route = $this->createRoute($methods, $pattern, $handler);
$this->routes[$route->getIdentifier()] = $route;
$routeName = $route->getName();
if ($routeName !== null && !isset($this->routesByName[$routeName])) {
$this->routesByName[$routeName] = $route;
}
$this->routeCounter++;
return $route;
}
/**
* @param string[] $methods
* @param callable|string $callable
*/
protected function createRoute(array $methods, string $pattern, $callable): RouteInterface
{
return new Route(
$methods,
$pattern,
$callable,
$this->responseFactory,
$this->callableResolver,
$this->container,
$this->defaultInvocationStrategy,
$this->routeGroups,
$this->routeCounter
);
}
}
slim/Slim/MiddlewareDispatcher.php 0000644 00000021372 15226547251 0013227 0 ustar 00 seedMiddlewareStack($kernel);
$this->callableResolver = $callableResolver;
$this->container = $container;
}
/**
* {@inheritdoc}
*/
public function seedMiddlewareStack(RequestHandlerInterface $kernel): void
{
$this->tip = $kernel;
}
/**
* Invoke the middleware stack
*/
public function handle(ServerRequestInterface $request): ResponseInterface
{
return $this->tip->handle($request);
}
/**
* Add a new middleware to the stack
*
* Middleware are organized as a stack. That means middleware
* that have been added before will be executed after the newly
* added one (last in, first out).
*
* @param MiddlewareInterface|string|callable $middleware
*/
public function add($middleware): MiddlewareDispatcherInterface
{
if ($middleware instanceof MiddlewareInterface) {
return $this->addMiddleware($middleware);
}
if (is_string($middleware)) {
return $this->addDeferred($middleware);
}
if (is_callable($middleware)) {
return $this->addCallable($middleware);
}
/** @phpstan-ignore-next-line */
throw new RuntimeException(
'A middleware must be an object/class name referencing an implementation of ' .
'MiddlewareInterface or a callable with a matching signature.'
);
}
/**
* Add a new middleware to the stack
*
* Middleware are organized as a stack. That means middleware
* that have been added before will be executed after the newly
* added one (last in, first out).
*/
public function addMiddleware(MiddlewareInterface $middleware): MiddlewareDispatcherInterface
{
$next = $this->tip;
$this->tip = new class ($middleware, $next) implements RequestHandlerInterface {
private MiddlewareInterface $middleware;
private RequestHandlerInterface $next;
public function __construct(MiddlewareInterface $middleware, RequestHandlerInterface $next)
{
$this->middleware = $middleware;
$this->next = $next;
}
public function handle(ServerRequestInterface $request): ResponseInterface
{
return $this->middleware->process($request, $this->next);
}
};
return $this;
}
/**
* Add a new middleware by class name
*
* Middleware are organized as a stack. That means middleware
* that have been added before will be executed after the newly
* added one (last in, first out).
*/
public function addDeferred(string $middleware): self
{
$next = $this->tip;
$this->tip = new class (
$middleware,
$next,
$this->container,
$this->callableResolver
) implements RequestHandlerInterface {
private string $middleware;
private RequestHandlerInterface $next;
private ?ContainerInterface $container;
private ?CallableResolverInterface $callableResolver;
public function __construct(
string $middleware,
RequestHandlerInterface $next,
?ContainerInterface $container = null,
?CallableResolverInterface $callableResolver = null
) {
$this->middleware = $middleware;
$this->next = $next;
$this->container = $container;
$this->callableResolver = $callableResolver;
}
public function handle(ServerRequestInterface $request): ResponseInterface
{
if ($this->callableResolver instanceof AdvancedCallableResolverInterface) {
$callable = $this->callableResolver->resolveMiddleware($this->middleware);
return $callable($request, $this->next);
}
$callable = null;
if ($this->callableResolver instanceof CallableResolverInterface) {
try {
$callable = $this->callableResolver->resolve($this->middleware);
} catch (RuntimeException $e) {
// Do Nothing
}
}
if (!$callable) {
$resolved = $this->middleware;
$instance = null;
$method = null;
// Check for Slim callable as `class:method`
if (preg_match(CallableResolver::$callablePattern, $resolved, $matches)) {
$resolved = $matches[1];
$method = $matches[2];
}
if ($this->container && $this->container->has($resolved)) {
$instance = $this->container->get($resolved);
if ($instance instanceof MiddlewareInterface) {
return $instance->process($request, $this->next);
}
} elseif (!function_exists($resolved)) {
if (!class_exists($resolved)) {
throw new RuntimeException(sprintf('Middleware %s does not exist', $resolved));
}
$instance = new $resolved($this->container);
}
if ($instance && $instance instanceof MiddlewareInterface) {
return $instance->process($request, $this->next);
}
$callable = $instance ?? $resolved;
if ($instance && $method) {
$callable = [$instance, $method];
}
if ($this->container && $callable instanceof Closure) {
$callable = $callable->bindTo($this->container);
}
}
if (!is_callable($callable)) {
throw new RuntimeException(
sprintf(
'Middleware %s is not resolvable',
$this->middleware
)
);
}
return $callable($request, $this->next);
}
};
return $this;
}
/**
* Add a (non-standard) callable middleware to the stack
*
* Middleware are organized as a stack. That means middleware
* that have been added before will be executed after the newly
* added one (last in, first out).
*/
public function addCallable(callable $middleware): self
{
$next = $this->tip;
if ($this->container && $middleware instanceof Closure) {
/** @var Closure $middleware */
$middleware = $middleware->bindTo($this->container);
}
$this->tip = new class ($middleware, $next) implements RequestHandlerInterface {
/**
* @var callable
*/
private $middleware;
/**
* @var RequestHandlerInterface
*/
private $next;
public function __construct(callable $middleware, RequestHandlerInterface $next)
{
$this->middleware = $middleware;
$this->next = $next;
}
public function handle(ServerRequestInterface $request): ResponseInterface
{
return ($this->middleware)($request, $this->next);
}
};
return $this;
}
}
slim/Slim/Exception/HttpBadRequestException.php 0000644 00000001110 15226547251 0015643 0 ustar 00 message = $message;
}
parent::__construct($request, $this->message, $this->code, $previous);
}
}
slim/Slim/Exception/HttpNotFoundException.php 0000644 00000001062 15226547251 0015346 0 ustar 00 request = $request;
}
public function getRequest(): ServerRequestInterface
{
return $this->request;
}
public function getTitle(): string
{
return $this->title;
}
public function setTitle(string $title): self
{
$this->title = $title;
return $this;
}
public function getDescription(): string
{
return $this->description;
}
public function setDescription(string $description): self
{
$this->description = $description;
return $this;
}
}
slim/Slim/Exception/HttpInternalServerErrorException.php 0000644 00000001121 15226547251 0017563 0 ustar 00 allowedMethods;
}
/**
* @param string[] $methods
*/
public function setAllowedMethods(array $methods): self
{
$this->allowedMethods = $methods;
$this->message = 'Method not allowed. Must be one of: ' . implode(', ', $methods);
return $this;
}
}
slim/Slim/Exception/HttpUnauthorizedException.php 0000644 00000001034 15226547251 0016272 0 ustar 00 container = $container;
}
/**
* {@inheritdoc}
*/
public function resolve($toResolve): callable
{
$toResolve = $this->prepareToResolve($toResolve);
if (is_callable($toResolve)) {
return $this->bindToContainer($toResolve);
}
$resolved = $toResolve;
if (is_string($toResolve)) {
$resolved = $this->resolveSlimNotation($toResolve);
$resolved[1] ??= '__invoke';
}
$callable = $this->assertCallable($resolved, $toResolve);
return $this->bindToContainer($callable);
}
/**
* {@inheritdoc}
*/
public function resolveRoute($toResolve): callable
{
return $this->resolveByPredicate($toResolve, [$this, 'isRoute'], 'handle');
}
/**
* {@inheritdoc}
*/
public function resolveMiddleware($toResolve): callable
{
return $this->resolveByPredicate($toResolve, [$this, 'isMiddleware'], 'process');
}
/**
* @param string|callable $toResolve
*
* @throws RuntimeException
*/
private function resolveByPredicate($toResolve, callable $predicate, string $defaultMethod): callable
{
$toResolve = $this->prepareToResolve($toResolve);
if (is_callable($toResolve)) {
return $this->bindToContainer($toResolve);
}
$resolved = $toResolve;
if ($predicate($toResolve)) {
$resolved = [$toResolve, $defaultMethod];
}
if (is_string($toResolve)) {
[$instance, $method] = $this->resolveSlimNotation($toResolve);
if ($method === null && $predicate($instance)) {
$method = $defaultMethod;
}
$resolved = [$instance, $method ?? '__invoke'];
}
$callable = $this->assertCallable($resolved, $toResolve);
return $this->bindToContainer($callable);
}
/**
* @param mixed $toResolve
*/
private function isRoute($toResolve): bool
{
return $toResolve instanceof RequestHandlerInterface;
}
/**
* @param mixed $toResolve
*/
private function isMiddleware($toResolve): bool
{
return $toResolve instanceof MiddlewareInterface;
}
/**
* @throws RuntimeException
*
* @return array{object, string|null} [Instance, Method Name]
*/
private function resolveSlimNotation(string $toResolve): array
{
preg_match(CallableResolver::$callablePattern, $toResolve, $matches);
[$class, $method] = $matches ? [$matches[1], $matches[2]] : [$toResolve, null];
/** @var string $class */
/** @var string|null $method */
if ($this->container && $this->container->has($class)) {
$instance = $this->container->get($class);
if (!is_object($instance)) {
throw new RuntimeException(sprintf('%s container entry is not an object', $class));
}
} else {
if (!class_exists($class)) {
if ($method) {
$class .= '::' . $method . '()';
}
throw new RuntimeException(sprintf('Callable %s does not exist', $class));
}
$instance = new $class($this->container);
}
return [$instance, $method];
}
/**
* @param mixed $resolved
* @param mixed $toResolve
*
* @throws RuntimeException
*/
private function assertCallable($resolved, $toResolve): callable
{
if (!is_callable($resolved)) {
if (is_callable($toResolve) || is_object($toResolve) || is_array($toResolve)) {
$formatedToResolve = ($toResolveJson = json_encode($toResolve)) !== false ? $toResolveJson : '';
} else {
$formatedToResolve = is_string($toResolve) ? $toResolve : '';
}
throw new RuntimeException(sprintf('%s is not resolvable', $formatedToResolve));
}
return $resolved;
}
private function bindToContainer(callable $callable): callable
{
if (is_array($callable) && $callable[0] instanceof Closure) {
$callable = $callable[0];
}
if ($this->container && $callable instanceof Closure) {
/** @var Closure $callable */
$callable = $callable->bindTo($this->container);
}
return $callable;
}
/**
* @param string|callable $toResolve
* @return string|callable
*/
private function prepareToResolve($toResolve)
{
if (!is_array($toResolve)) {
return $toResolve;
}
$candidate = $toResolve;
$class = array_shift($candidate);
$method = array_shift($candidate);
if (is_string($class) && is_string($method)) {
return $class . ':' . $method;
}
return $toResolve;
}
}
slim/Slim/Interfaces/RouteCollectorProxyInterface.php 0000644 00000006651 15226547251 0017061 0 ustar 00
*/
public function getArguments(): array;
/**
* Set a route argument
*/
public function setArgument(string $name, string $value): RouteInterface;
/**
* Replace route arguments
*
* @param array $arguments
*/
public function setArguments(array $arguments): self;
/**
* @param MiddlewareInterface|string|callable $middleware
*/
public function add($middleware): self;
public function addMiddleware(MiddlewareInterface $middleware): self;
/**
* Prepare the route for use
*
* @param array $arguments
*/
public function prepare(array $arguments): self;
/**
* Run route
*
* This method traverses the middleware stack, including the route's callable
* and captures the resultant HTTP response object. It then sends the response
* back to the Application.
*/
public function run(ServerRequestInterface $request): ResponseInterface;
}
slim/Slim/Interfaces/ServerRequestCreatorInterface.php 0000644 00000000555 15226547251 0017206 0 ustar 00 $routeArguments The route's placeholder arguments
*
* @return ResponseInterface The response from the callable.
*/
public function __invoke(
callable $callable,
ServerRequestInterface $request,
ResponseInterface $response,
array $routeArguments
): ResponseInterface;
}
slim/Slim/Interfaces/ErrorHandlerInterface.php 0000644 00000001047 15226547251 0015433 0 ustar 00 getPath()
*/
public function computeRoutingResults(string $uri, string $method): RoutingResults;
public function resolveRoute(string $identifier): RouteInterface;
}
slim/Slim/Interfaces/RouteCollectorInterface.php 0000644 00000004741 15226547251 0016015 0 ustar 00 $data Named argument replacement data
* @param array $queryParams Optional query string parameters
*
* @throws RuntimeException If named route does not exist
* @throws InvalidArgumentException If required data not provided
*/
public function relativeUrlFor(string $routeName, array $data = [], array $queryParams = []): string;
/**
* Build the path for a named route including the base path
*
* @param string $routeName Route name
* @param array $data Named argument replacement data
* @param array $queryParams Optional query string parameters
*
* @throws RuntimeException If named route does not exist
* @throws InvalidArgumentException If required data not provided
*/
public function urlFor(string $routeName, array $data = [], array $queryParams = []): string;
/**
* Get fully qualified URL for named route
*
* @param UriInterface $uri
* @param string $routeName Route name
* @param array $data Named argument replacement data
* @param array $queryParams Optional query string parameters
*/
public function fullUrlFor(UriInterface $uri, string $routeName, array $data = [], array $queryParams = []): string;
}
slim/Slim/Interfaces/Psr17FactoryInterface.php 0000644 00000002323 15226547251 0015306 0 ustar 00 has(ResponseFactoryInterface::class)
&& (
$responseFactoryFromContainer = $container->get(ResponseFactoryInterface::class)
) instanceof ResponseFactoryInterface
? $responseFactoryFromContainer
: self::determineResponseFactory();
$callableResolver = $container->has(CallableResolverInterface::class)
&& (
$callableResolverFromContainer = $container->get(CallableResolverInterface::class)
) instanceof CallableResolverInterface
? $callableResolverFromContainer
: null;
$routeCollector = $container->has(RouteCollectorInterface::class)
&& (
$routeCollectorFromContainer = $container->get(RouteCollectorInterface::class)
) instanceof RouteCollectorInterface
? $routeCollectorFromContainer
: null;
$routeResolver = $container->has(RouteResolverInterface::class)
&& (
$routeResolverFromContainer = $container->get(RouteResolverInterface::class)
) instanceof RouteResolverInterface
? $routeResolverFromContainer
: null;
$middlewareDispatcher = $container->has(MiddlewareDispatcherInterface::class)
&& (
$middlewareDispatcherFromContainer = $container->get(MiddlewareDispatcherInterface::class)
) instanceof MiddlewareDispatcherInterface
? $middlewareDispatcherFromContainer
: null;
return new App(
$responseFactory,
$container,
$callableResolver,
$routeCollector,
$routeResolver,
$middlewareDispatcher
);
}
/**
* @throws RuntimeException
*/
public static function determineResponseFactory(): ResponseFactoryInterface
{
if (static::$responseFactory) {
if (static::$streamFactory) {
return static::attemptResponseFactoryDecoration(static::$responseFactory, static::$streamFactory);
}
return static::$responseFactory;
}
$psr17FactoryProvider = static::$psr17FactoryProvider ?? new Psr17FactoryProvider();
/** @var Psr17Factory $psr17factory */
foreach ($psr17FactoryProvider->getFactories() as $psr17factory) {
if ($psr17factory::isResponseFactoryAvailable()) {
$responseFactory = $psr17factory::getResponseFactory();
if (static::$streamFactory || $psr17factory::isStreamFactoryAvailable()) {
$streamFactory = static::$streamFactory ?? $psr17factory::getStreamFactory();
return static::attemptResponseFactoryDecoration($responseFactory, $streamFactory);
}
return $responseFactory;
}
}
throw new RuntimeException(
"Could not detect any PSR-17 ResponseFactory implementations. " .
"Please install a supported implementation in order to use `AppFactory::create()`. " .
"See https://github.com/slimphp/Slim/blob/4.x/README.md for a list of supported implementations."
);
}
protected static function attemptResponseFactoryDecoration(
ResponseFactoryInterface $responseFactory,
StreamFactoryInterface $streamFactory
): ResponseFactoryInterface {
if (
static::$slimHttpDecoratorsAutomaticDetectionEnabled
&& SlimHttpPsr17Factory::isResponseFactoryAvailable()
) {
return SlimHttpPsr17Factory::createDecoratedResponseFactory($responseFactory, $streamFactory);
}
return $responseFactory;
}
public static function setPsr17FactoryProvider(Psr17FactoryProviderInterface $psr17FactoryProvider): void
{
static::$psr17FactoryProvider = $psr17FactoryProvider;
}
public static function setResponseFactory(ResponseFactoryInterface $responseFactory): void
{
static::$responseFactory = $responseFactory;
}
public static function setStreamFactory(StreamFactoryInterface $streamFactory): void
{
static::$streamFactory = $streamFactory;
}
public static function setContainer(ContainerInterface $container): void
{
static::$container = $container;
}
public static function setCallableResolver(CallableResolverInterface $callableResolver): void
{
static::$callableResolver = $callableResolver;
}
public static function setRouteCollector(RouteCollectorInterface $routeCollector): void
{
static::$routeCollector = $routeCollector;
}
public static function setRouteResolver(RouteResolverInterface $routeResolver): void
{
static::$routeResolver = $routeResolver;
}
public static function setMiddlewareDispatcher(MiddlewareDispatcherInterface $middlewareDispatcher): void
{
static::$middlewareDispatcher = $middlewareDispatcher;
}
public static function setSlimHttpDecoratorsAutomaticDetection(bool $enabled): void
{
static::$slimHttpDecoratorsAutomaticDetectionEnabled = $enabled;
}
}
Slim/Factory/Psr17/Psr17Factory.php 0000644 00000005354 15227044554 0012767 0 ustar 00 serverRequestCreator = $serverRequestCreator;
$this->serverRequestCreatorMethod = $serverRequestCreatorMethod;
}
/**
* {@inheritdoc}
*/
public function createServerRequestFromGlobals(): ServerRequestInterface
{
/** @var callable $callable */
$callable = [$this->serverRequestCreator, $this->serverRequestCreatorMethod];
return (Closure::fromCallable($callable))();
}
}
Slim/Factory/Psr17/SlimHttpPsr17Factory.php 0000644 00000002170 15227044554 0014445 0 ustar 00 serverRequestCreator = $serverRequestCreator;
}
/**
* {@inheritdoc}
*/
public function createServerRequestFromGlobals(): ServerRequestInterface
{
if (!static::isServerRequestDecoratorAvailable()) {
throw new RuntimeException('The Slim-Http ServerRequest decorator is not available.');
}
$request = $this->serverRequestCreator->createServerRequestFromGlobals();
if (
!((
$decoratedServerRequest = new static::$serverRequestDecoratorClass($request)
) instanceof ServerRequestInterface)
) {
throw new RuntimeException(get_called_class() . ' could not instantiate a decorated server request.');
}
return $decoratedServerRequest;
}
public static function isServerRequestDecoratorAvailable(): bool
{
return class_exists(static::$serverRequestDecoratorClass);
}
}
Slim/Factory/Psr17/SlimPsr17Factory.php 0000644 00000001130 15227044554 0013600 0 ustar 00 getFactories() as $psr17Factory) {
if ($psr17Factory::isServerRequestCreatorAvailable()) {
$serverRequestCreator = $psr17Factory::getServerRequestCreator();
return static::attemptServerRequestCreatorDecoration($serverRequestCreator);
}
}
throw new RuntimeException(
"Could not detect any ServerRequest creator implementations. " .
"Please install a supported implementation in order to use `App::run()` " .
"without having to pass in a `ServerRequest` object. " .
"See https://github.com/slimphp/Slim/blob/4.x/README.md for a list of supported implementations."
);
}
protected static function attemptServerRequestCreatorDecoration(
ServerRequestCreatorInterface $serverRequestCreator
): ServerRequestCreatorInterface {
if (
static::$slimHttpDecoratorsAutomaticDetectionEnabled
&& SlimHttpServerRequestCreator::isServerRequestDecoratorAvailable()
) {
return new SlimHttpServerRequestCreator($serverRequestCreator);
}
return $serverRequestCreator;
}
public static function setPsr17FactoryProvider(Psr17FactoryProviderInterface $psr17FactoryProvider): void
{
static::$psr17FactoryProvider = $psr17FactoryProvider;
}
public static function setServerRequestCreator(ServerRequestCreatorInterface $serverRequestCreator): void
{
self::$serverRequestCreator = $serverRequestCreator;
}
public static function setSlimHttpDecoratorsAutomaticDetection(bool $enabled): void
{
static::$slimHttpDecoratorsAutomaticDetectionEnabled = $enabled;
}
}
Slim/App.php 0000644 00000015157 15227044554 0006722 0 ustar 00 routeResolver = $routeResolver ?? new RouteResolver($this->routeCollector);
$routeRunner = new RouteRunner($this->routeResolver, $this->routeCollector->getRouteParser(), $this);
if (!$middlewareDispatcher) {
$middlewareDispatcher = new MiddlewareDispatcher($routeRunner, $this->callableResolver, $container);
} else {
$middlewareDispatcher->seedMiddlewareStack($routeRunner);
}
$this->middlewareDispatcher = $middlewareDispatcher;
}
/**
* @return RouteResolverInterface
*/
public function getRouteResolver(): RouteResolverInterface
{
return $this->routeResolver;
}
/**
* @return MiddlewareDispatcherInterface
*/
public function getMiddlewareDispatcher(): MiddlewareDispatcherInterface
{
return $this->middlewareDispatcher;
}
/**
* @param MiddlewareInterface|string|callable $middleware
*/
public function add($middleware): self
{
$this->middlewareDispatcher->add($middleware);
return $this;
}
/**
* @param MiddlewareInterface $middleware
*/
public function addMiddleware(MiddlewareInterface $middleware): self
{
$this->middlewareDispatcher->addMiddleware($middleware);
return $this;
}
/**
* Add the Slim built-in routing middleware to the app middleware stack
*
* This method can be used to control middleware order and is not required for default routing operation.
*
* @return RoutingMiddleware
*/
public function addRoutingMiddleware(): RoutingMiddleware
{
$routingMiddleware = new RoutingMiddleware(
$this->getRouteResolver(),
$this->getRouteCollector()->getRouteParser()
);
$this->add($routingMiddleware);
return $routingMiddleware;
}
/**
* Add the Slim built-in error middleware to the app middleware stack
*
* @param bool $displayErrorDetails
* @param bool $logErrors
* @param bool $logErrorDetails
* @param LoggerInterface|null $logger
*
* @return ErrorMiddleware
*/
public function addErrorMiddleware(
bool $displayErrorDetails,
bool $logErrors,
bool $logErrorDetails,
?LoggerInterface $logger = null
): ErrorMiddleware {
$errorMiddleware = new ErrorMiddleware(
$this->getCallableResolver(),
$this->getResponseFactory(),
$displayErrorDetails,
$logErrors,
$logErrorDetails,
$logger
);
$this->add($errorMiddleware);
return $errorMiddleware;
}
/**
* Add the Slim body parsing middleware to the app middleware stack
*
* @param callable[] $bodyParsers
*
* @return BodyParsingMiddleware
*/
public function addBodyParsingMiddleware(array $bodyParsers = []): BodyParsingMiddleware
{
$bodyParsingMiddleware = new BodyParsingMiddleware($bodyParsers);
$this->add($bodyParsingMiddleware);
return $bodyParsingMiddleware;
}
/**
* Run application
*
* This method traverses the application middleware stack and then sends the
* resultant Response object to the HTTP client.
*
* @param ServerRequestInterface|null $request
* @return void
*/
public function run(?ServerRequestInterface $request = null): void
{
if (!$request) {
$serverRequestCreator = ServerRequestCreatorFactory::create();
$request = $serverRequestCreator->createServerRequestFromGlobals();
}
$response = $this->handle($request);
$responseEmitter = new ResponseEmitter();
$responseEmitter->emit($response);
}
/**
* Handle a request
*
* This method traverses the application middleware stack and then returns the
* resultant Response object.
*
* @param ServerRequestInterface $request
* @return ResponseInterface
*/
public function handle(ServerRequestInterface $request): ResponseInterface
{
$response = $this->middlewareDispatcher->handle($request);
/**
* This is to be in compliance with RFC 2616, Section 9.
* If the incoming request method is HEAD, we need to ensure that the response body
* is empty as the request may fall back on a GET route handler due to FastRoute's
* routing logic which could potentially append content to the response body
* https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.4
*/
$method = strtoupper($request->getMethod());
if ($method === 'HEAD') {
$emptyBody = $this->responseFactory->createResponse()->getBody();
return $response->withBody($emptyBody);
}
return $response;
}
}
Slim/Handlers/Strategies/RequestResponseArgs.php 0000644 00000001733 15227044554 0016033 0 ustar 00 $routeArguments
*/
public function __invoke(
callable $callable,
ServerRequestInterface $request,
ResponseInterface $response,
array $routeArguments
): ResponseInterface {
return $callable($request, $response, ...array_values($routeArguments));
}
}
Slim/Handlers/Strategies/RequestResponseNamedArgs.php 0000644 00000002212 15227044554 0016771 0 ustar 00 = 8.0.0');
}
}
/**
* Invoke a route callable with request, response and all route parameters
* as individual arguments.
*
* @param array $routeArguments
*/
public function __invoke(
callable $callable,
ServerRequestInterface $request,
ResponseInterface $response,
array $routeArguments
): ResponseInterface {
return $callable($request, $response, ...$routeArguments);
}
}
Slim/Handlers/Strategies/RequestResponse.php 0000644 00000002050 15227044554 0015207 0 ustar 00 $routeArguments
*/
public function __invoke(
callable $callable,
ServerRequestInterface $request,
ResponseInterface $response,
array $routeArguments
): ResponseInterface {
foreach ($routeArguments as $k => $v) {
$request = $request->withAttribute($k, $v);
}
return $callable($request, $response, $routeArguments);
}
}
Slim/Handlers/Strategies/RequestHandler.php 0000644 00000002460 15227044554 0014773 0 ustar 00 appendRouteArgumentsToRequestAttributes = $appendRouteArgumentsToRequestAttributes;
}
/**
* Invoke a route callable that implements RequestHandlerInterface
*
* @param array $routeArguments
*/
public function __invoke(
callable $callable,
ServerRequestInterface $request,
ResponseInterface $response,
array $routeArguments
): ResponseInterface {
if ($this->appendRouteArgumentsToRequestAttributes) {
foreach ($routeArguments as $k => $v) {
$request = $request->withAttribute($k, $v);
}
}
return $callable($request);
}
}
Slim/Handlers/ErrorHandler.php 0000644 00000023111 15227044554 0012316 0 ustar 00
*/
protected array $errorRenderers = [
'application/json' => JsonErrorRenderer::class,
'application/xml' => XmlErrorRenderer::class,
'text/xml' => XmlErrorRenderer::class,
'text/html' => HtmlErrorRenderer::class,
'text/plain' => PlainTextErrorRenderer::class,
];
protected bool $displayErrorDetails = false;
protected bool $logErrors;
protected bool $logErrorDetails = false;
protected ?string $contentType = null;
protected ?string $method = null;
protected ServerRequestInterface $request;
protected Throwable $exception;
protected int $statusCode;
protected CallableResolverInterface $callableResolver;
protected ResponseFactoryInterface $responseFactory;
protected LoggerInterface $logger;
public function __construct(
CallableResolverInterface $callableResolver,
ResponseFactoryInterface $responseFactory,
?LoggerInterface $logger = null
) {
$this->callableResolver = $callableResolver;
$this->responseFactory = $responseFactory;
$this->logger = $logger ?: $this->getDefaultLogger();
}
/**
* Invoke error handler
*
* @param ServerRequestInterface $request The most recent Request object
* @param Throwable $exception The caught Exception object
* @param bool $displayErrorDetails Whether or not to display the error details
* @param bool $logErrors Whether or not to log errors
* @param bool $logErrorDetails Whether or not to log error details
*/
public function __invoke(
ServerRequestInterface $request,
Throwable $exception,
bool $displayErrorDetails,
bool $logErrors,
bool $logErrorDetails
): ResponseInterface {
$this->displayErrorDetails = $displayErrorDetails;
$this->logErrors = $logErrors;
$this->logErrorDetails = $logErrorDetails;
$this->request = $request;
$this->exception = $exception;
$this->method = $request->getMethod();
$this->statusCode = $this->determineStatusCode();
if ($this->contentType === null) {
$this->contentType = $this->determineContentType($request);
}
if ($logErrors) {
$this->writeToErrorLog();
}
return $this->respond();
}
/**
* Force the content type for all error handler responses.
*
* @param string|null $contentType The content type
*/
public function forceContentType(?string $contentType): void
{
$this->contentType = $contentType;
}
protected function determineStatusCode(): int
{
if ($this->method === 'OPTIONS') {
return 200;
}
if ($this->exception instanceof HttpException) {
return $this->exception->getCode();
}
return 500;
}
/**
* Determine which content type we know about is wanted using Accept header
*
* Note: This method is a bare-bones implementation designed specifically for
* Slim's error handling requirements. Consider a fully-feature solution such
* as willdurand/negotiation for any other situation.
*/
protected function determineContentType(ServerRequestInterface $request): ?string
{
$acceptHeader = $request->getHeaderLine('Accept');
$selectedContentTypes = array_intersect(
explode(',', $acceptHeader),
array_keys($this->errorRenderers)
);
$count = count($selectedContentTypes);
if ($count) {
$current = current($selectedContentTypes);
/**
* Ensure other supported content types take precedence over text/plain
* when multiple content types are provided via Accept header.
*/
if ($current === 'text/plain' && $count > 1) {
$next = next($selectedContentTypes);
if (is_string($next)) {
return $next;
}
}
if (is_string($current)) {
return $current;
}
}
if (preg_match('/\+(json|xml)/', $acceptHeader, $matches)) {
$mediaType = 'application/' . $matches[1];
if (array_key_exists($mediaType, $this->errorRenderers)) {
return $mediaType;
}
}
return null;
}
/**
* Determine which renderer to use based on content type
*
* @throws RuntimeException
*/
protected function determineRenderer(): callable
{
if ($this->contentType !== null && array_key_exists($this->contentType, $this->errorRenderers)) {
$renderer = $this->errorRenderers[$this->contentType];
} else {
$renderer = $this->defaultErrorRenderer;
}
return $this->callableResolver->resolve($renderer);
}
/**
* Register an error renderer for a specific content-type
*
* @param string $contentType The content-type this renderer should be registered to
* @param ErrorRendererInterface|string|callable $errorRenderer The error renderer
*/
public function registerErrorRenderer(string $contentType, $errorRenderer): void
{
$this->errorRenderers[$contentType] = $errorRenderer;
}
/**
* Set the default error renderer
*
* @param string $contentType The content type of the default error renderer
* @param ErrorRendererInterface|string|callable $errorRenderer The default error renderer
*/
public function setDefaultErrorRenderer(string $contentType, $errorRenderer): void
{
$this->defaultErrorRendererContentType = $contentType;
$this->defaultErrorRenderer = $errorRenderer;
}
/**
* Set the renderer for the error logger
*
* @param ErrorRendererInterface|string|callable $logErrorRenderer
*/
public function setLogErrorRenderer($logErrorRenderer): void
{
$this->logErrorRenderer = $logErrorRenderer;
}
/**
* Write to the error log if $logErrors has been set to true
*/
protected function writeToErrorLog(): void
{
$renderer = $this->callableResolver->resolve($this->logErrorRenderer);
$error = $renderer($this->exception, $this->logErrorDetails);
if (!$this->displayErrorDetails) {
$error .= "\nTips: To display error details in HTTP response ";
$error .= 'set "displayErrorDetails" to true in the ErrorHandler constructor.';
}
$this->logError($error);
}
/**
* Wraps the error_log function so that this can be easily tested
*/
protected function logError(string $error): void
{
$this->logger->error($error);
}
/**
* Returns a default logger implementation.
*/
protected function getDefaultLogger(): LoggerInterface
{
return new Logger();
}
protected function respond(): ResponseInterface
{
$response = $this->responseFactory->createResponse($this->statusCode);
if ($this->contentType !== null && array_key_exists($this->contentType, $this->errorRenderers)) {
$response = $response->withHeader('Content-type', $this->contentType);
} else {
$response = $response->withHeader('Content-type', $this->defaultErrorRendererContentType);
}
if ($this->exception instanceof HttpMethodNotAllowedException) {
$allowedMethods = implode(', ', $this->exception->getAllowedMethods());
$response = $response->withHeader('Allow', $allowedMethods);
}
$renderer = $this->determineRenderer();
$body = call_user_func($renderer, $this->exception, $this->displayErrorDetails);
if ($body !== false) {
/** @var string $body */
$response->getBody()->write($body);
}
return $response;
}
}
Slim/Logger.php 0000644 00000001175 15227044554 0007414 0 ustar 00 $context
*
* @throws InvalidArgumentException
*/
public function log($level, $message, array $context = []): void
{
error_log((string) $message);
}
}
Slim/ResponseEmitter.php 0000644 00000006771 15227044554 0011334 0 ustar 00 responseChunkSize = $responseChunkSize;
}
/**
* Send the response the client
*/
public function emit(ResponseInterface $response): void
{
$isEmpty = $this->isResponseEmpty($response);
if (headers_sent() === false) {
$this->emitHeaders($response);
// Set the status _after_ the headers, because of PHP's "helpful" behavior with location headers.
// See https://github.com/slimphp/Slim/issues/1730
$this->emitStatusLine($response);
}
if (!$isEmpty) {
$this->emitBody($response);
}
}
/**
* Emit Response Headers
*/
private function emitHeaders(ResponseInterface $response): void
{
foreach ($response->getHeaders() as $name => $values) {
$first = strtolower($name) !== 'set-cookie';
foreach ($values as $value) {
$header = sprintf('%s: %s', $name, $value);
header($header, $first);
$first = false;
}
}
}
/**
* Emit Status Line
*/
private function emitStatusLine(ResponseInterface $response): void
{
$statusLine = sprintf(
'HTTP/%s %s %s',
$response->getProtocolVersion(),
$response->getStatusCode(),
$response->getReasonPhrase()
);
header($statusLine, true, $response->getStatusCode());
}
/**
* Emit Body
*/
private function emitBody(ResponseInterface $response): void
{
$body = $response->getBody();
if ($body->isSeekable()) {
$body->rewind();
}
$amountToRead = (int) $response->getHeaderLine('Content-Length');
if (!$amountToRead) {
$amountToRead = $body->getSize();
}
if ($amountToRead) {
while ($amountToRead > 0 && !$body->eof()) {
$length = min($this->responseChunkSize, $amountToRead);
$data = $body->read($length);
echo $data;
$amountToRead -= strlen($data);
if (connection_status() !== CONNECTION_NORMAL) {
break;
}
}
} else {
while (!$body->eof()) {
echo $body->read($this->responseChunkSize);
if (connection_status() !== CONNECTION_NORMAL) {
break;
}
}
}
}
/**
* Asserts response body is empty or status code is 204, 205 or 304
*/
public function isResponseEmpty(ResponseInterface $response): bool
{
if (in_array($response->getStatusCode(), [204, 205, 304], true)) {
return true;
}
$stream = $response->getBody();
$seekable = $stream->isSeekable();
if ($seekable) {
$stream->rewind();
}
return $seekable ? $stream->read(1) === '' : $stream->eof();
}
}
Slim/Error/Renderers/JsonErrorRenderer.php 0000644 00000002642 15227044554 0014631 0 ustar 00 $this->getErrorTitle($exception)];
if ($displayErrorDetails) {
$error['exception'] = [];
do {
$error['exception'][] = $this->formatExceptionFragment($exception);
} while ($exception = $exception->getPrevious());
}
return (string) json_encode($error, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
}
/**
* @return array
*/
private function formatExceptionFragment(Throwable $exception): array
{
/** @var int|string $code */
$code = $exception->getCode();
return [
'type' => get_class($exception),
'code' => $code,
'message' => $exception->getMessage(),
'file' => $exception->getFile(),
'line' => $exception->getLine(),
];
}
}
Slim/Error/Renderers/XmlErrorRenderer.php 0000644 00000003200 15227044554 0014447 0 ustar 00 \n";
$xml .= "\n " . $this->createCdataSection($this->getErrorTitle($exception)) . "\n";
if ($displayErrorDetails) {
do {
$xml .= " \n";
$xml .= ' ' . get_class($exception) . "\n";
$xml .= ' ' . $exception->getCode() . "\n";
$xml .= ' ' . $this->createCdataSection($exception->getMessage()) . "\n";
$xml .= ' ' . $exception->getFile() . "\n";
$xml .= ' ' . $exception->getLine() . "\n";
$xml .= " \n";
} while ($exception = $exception->getPrevious());
}
$xml .= '';
return $xml;
}
/**
* Returns a CDATA section with the given content.
*/
private function createCdataSection(string $content): string
{
return sprintf('', str_replace(']]>', ']]]]>', $content));
}
}
Slim/Error/Renderers/HtmlErrorRenderer.php 0000644 00000005322 15227044554 0014622 0 ustar 00 The application could not run because of the following error:';
$html .= 'Details
';
$html .= $this->renderExceptionFragment($exception);
} else {
$html = "{$this->getErrorDescription($exception)}
";
}
return $this->renderHtmlBody($this->getErrorTitle($exception), $html);
}
private function renderExceptionFragment(Throwable $exception): string
{
$html = sprintf('Type: %s
', get_class($exception));
/** @var int|string $code */
$code = $exception->getCode();
$html .= sprintf('Code: %s
', $code);
$html .= sprintf('Message: %s
', htmlentities($exception->getMessage()));
$html .= sprintf('File: %s
', $exception->getFile());
$html .= sprintf('Line: %s
', $exception->getLine());
$html .= 'Trace
';
$html .= sprintf('%s
', htmlentities($exception->getTraceAsString()));
return $html;
}
public function renderHtmlBody(string $title = '', string $html = ''): string
{
return sprintf(
'' .
'' .
' ' .
' ' .
' ' .
' %s' .
' ' .
' ' .
' ' .
' %s
' .
' %s
' .
' Go Back' .
' ' .
'',
$title,
$title,
$html
);
}
}
Slim/Error/Renderers/PlainTextErrorRenderer.php 0000644 00000002756 15227044554 0015636 0 ustar 00 getErrorTitle($exception)}\n";
if ($displayErrorDetails) {
$text .= $this->formatExceptionFragment($exception);
while ($exception = $exception->getPrevious()) {
$text .= "\nPrevious Error:\n";
$text .= $this->formatExceptionFragment($exception);
}
}
return $text;
}
private function formatExceptionFragment(Throwable $exception): string
{
$text = sprintf("Type: %s\n", get_class($exception));
$code = $exception->getCode();
/** @var int|string $code */
$text .= sprintf("Code: %s\n", $code);
$text .= sprintf("Message: %s\n", htmlentities($exception->getMessage()));
$text .= sprintf("File: %s\n", $exception->getFile());
$text .= sprintf("Line: %s\n", $exception->getLine());
$text .= sprintf('Trace: %s', $exception->getTraceAsString());
return $text;
}
}
Slim/Error/AbstractErrorRenderer.php 0000644 00000002260 15227044554 0013526 0 ustar 00 getTitle();
}
return $this->defaultErrorTitle;
}
protected function getErrorDescription(Throwable $exception): string
{
if ($exception instanceof HttpException) {
return $exception->getDescription();
}
return $this->defaultErrorDescription;
}
}
Slim/Middleware/RoutingMiddleware.php 0000644 00000006321 15227044554 0013675 0 ustar 00 routeResolver = $routeResolver;
$this->routeParser = $routeParser;
}
/**
* @throws HttpNotFoundException
* @throws HttpMethodNotAllowedException
* @throws RuntimeException
*/
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
$request = $this->performRouting($request);
return $handler->handle($request);
}
/**
* Perform routing
*
* @param ServerRequestInterface $request PSR7 Server Request
*
* @throws HttpNotFoundException
* @throws HttpMethodNotAllowedException
* @throws RuntimeException
*/
public function performRouting(ServerRequestInterface $request): ServerRequestInterface
{
$request = $request->withAttribute(RouteContext::ROUTE_PARSER, $this->routeParser);
$routingResults = $this->resolveRoutingResultsFromRequest($request);
$routeStatus = $routingResults->getRouteStatus();
$request = $request->withAttribute(RouteContext::ROUTING_RESULTS, $routingResults);
switch ($routeStatus) {
case RoutingResults::FOUND:
$routeArguments = $routingResults->getRouteArguments();
$routeIdentifier = $routingResults->getRouteIdentifier() ?? '';
$route = $this->routeResolver
->resolveRoute($routeIdentifier)
->prepare($routeArguments);
return $request->withAttribute(RouteContext::ROUTE, $route);
case RoutingResults::NOT_FOUND:
throw new HttpNotFoundException($request);
case RoutingResults::METHOD_NOT_ALLOWED:
$exception = new HttpMethodNotAllowedException($request);
$exception->setAllowedMethods($routingResults->getAllowedMethods());
throw $exception;
default:
throw new RuntimeException('An unexpected error occurred while performing routing.');
}
}
/**
* Resolves the route from the given request
*/
protected function resolveRoutingResultsFromRequest(ServerRequestInterface $request): RoutingResults
{
return $this->routeResolver->computeRoutingResults(
$request->getUri()->getPath(),
$request->getMethod()
);
}
}
Slim/Middleware/BodyParsingMiddleware.php 0000644 00000013324 15227044554 0014470 0 ustar 00 callable
*/
public function __construct(array $bodyParsers = [])
{
$this->registerDefaultBodyParsers();
foreach ($bodyParsers as $mediaType => $parser) {
$this->registerBodyParser($mediaType, $parser);
}
}
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
$parsedBody = $request->getParsedBody();
if (empty($parsedBody)) {
$parsedBody = $this->parseBody($request);
$request = $request->withParsedBody($parsedBody);
}
return $handler->handle($request);
}
/**
* @param string $mediaType A HTTP media type (excluding content-type params).
* @param callable $callable A callable that returns parsed contents for media type.
*/
public function registerBodyParser(string $mediaType, callable $callable): self
{
$this->bodyParsers[$mediaType] = $callable;
return $this;
}
/**
* @param string $mediaType A HTTP media type (excluding content-type params).
*/
public function hasBodyParser(string $mediaType): bool
{
return isset($this->bodyParsers[$mediaType]);
}
/**
* @param string $mediaType A HTTP media type (excluding content-type params).
* @throws RuntimeException
*/
public function getBodyParser(string $mediaType): callable
{
if (!isset($this->bodyParsers[$mediaType])) {
throw new RuntimeException('No parser for type ' . $mediaType);
}
return $this->bodyParsers[$mediaType];
}
protected function registerDefaultBodyParsers(): void
{
$this->registerBodyParser('application/json', static function ($input) {
$result = json_decode($input, true);
if (!is_array($result)) {
return null;
}
return $result;
});
$this->registerBodyParser('application/x-www-form-urlencoded', static function ($input) {
parse_str($input, $data);
return $data;
});
$xmlCallable = static function ($input) {
$backup = self::disableXmlEntityLoader(true);
$backup_errors = libxml_use_internal_errors(true);
$result = simplexml_load_string($input);
self::disableXmlEntityLoader($backup);
libxml_clear_errors();
libxml_use_internal_errors($backup_errors);
if ($result === false) {
return null;
}
return $result;
};
$this->registerBodyParser('application/xml', $xmlCallable);
$this->registerBodyParser('text/xml', $xmlCallable);
}
/**
* @return null|array|object
*/
protected function parseBody(ServerRequestInterface $request)
{
$mediaType = $this->getMediaType($request);
if ($mediaType === null) {
return null;
}
// Check if this specific media type has a parser registered first
if (!isset($this->bodyParsers[$mediaType])) {
// If not, look for a media type with a structured syntax suffix (RFC 6839)
$parts = explode('+', $mediaType);
if (count($parts) >= 2) {
$mediaType = 'application/' . $parts[count($parts) - 1];
}
}
if (isset($this->bodyParsers[$mediaType])) {
$body = (string)$request->getBody();
$parsed = $this->bodyParsers[$mediaType]($body);
if ($parsed !== null && !is_object($parsed) && !is_array($parsed)) {
throw new RuntimeException(
'Request body media type parser return value must be an array, an object, or null'
);
}
return $parsed;
}
return null;
}
/**
* @return string|null The serverRequest media type, minus content-type params
*/
protected function getMediaType(ServerRequestInterface $request): ?string
{
$contentType = $request->getHeader('Content-Type')[0] ?? null;
if (is_string($contentType) && trim($contentType) !== '') {
$contentTypeParts = explode(';', $contentType);
return strtolower(trim($contentTypeParts[0]));
}
return null;
}
protected static function disableXmlEntityLoader(bool $disable): bool
{
if (LIBXML_VERSION >= 20900) {
// libxml >= 2.9.0 disables entity loading by default, so it is
// safe to skip the real call (deprecated in PHP 8).
return true;
}
// @codeCoverageIgnoreStart
return libxml_disable_entity_loader($disable);
// @codeCoverageIgnoreEnd
}
}
Slim/Middleware/MethodOverrideMiddleware.php 0000644 00000002253 15227044554 0015166 0 ustar 00 getHeaderLine('X-Http-Method-Override');
if ($methodHeader) {
$request = $request->withMethod($methodHeader);
} elseif (strtoupper($request->getMethod()) === 'POST') {
$body = $request->getParsedBody();
if (is_array($body) && !empty($body['_METHOD'])) {
$request = $request->withMethod($body['_METHOD']);
}
if ($request->getBody()->eof()) {
$request->getBody()->rewind();
}
}
return $handler->handle($request);
}
}
Slim/Middleware/OutputBufferingMiddleware.php 0000644 00000004053 15227044554 0015376 0 ustar 00 streamFactory = $streamFactory;
$this->style = $style;
if (!in_array($style, [static::APPEND, static::PREPEND], true)) {
throw new InvalidArgumentException("Invalid style `{$style}`. Must be `append` or `prepend`");
}
}
/**
* @throws Throwable
*/
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
try {
ob_start();
$response = $handler->handle($request);
$output = ob_get_clean();
} catch (Throwable $e) {
ob_end_clean();
throw $e;
}
if (!empty($output)) {
if ($this->style === static::PREPEND) {
$body = $this->streamFactory->createStream();
$body->write($output . $response->getBody());
$response = $response->withBody($body);
} elseif ($this->style === static::APPEND && $response->getBody()->isWritable()) {
$response->getBody()->write($output);
}
}
return $response;
}
}
Slim/Middleware/ErrorMiddleware.php 0000644 00000014666 15227044554 0013352 0 ustar 00 callableResolver = $callableResolver;
$this->responseFactory = $responseFactory;
$this->displayErrorDetails = $displayErrorDetails;
$this->logErrors = $logErrors;
$this->logErrorDetails = $logErrorDetails;
$this->logger = $logger;
}
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
try {
return $handler->handle($request);
} catch (Throwable $e) {
return $this->handleException($request, $e);
}
}
public function handleException(ServerRequestInterface $request, Throwable $exception): ResponseInterface
{
if ($exception instanceof HttpException) {
$request = $exception->getRequest();
}
$exceptionType = get_class($exception);
$handler = $this->getErrorHandler($exceptionType);
return $handler($request, $exception, $this->displayErrorDetails, $this->logErrors, $this->logErrorDetails);
}
/**
* Get callable to handle scenarios where an error
* occurs when processing the current request.
*
* @param string $type Exception/Throwable name. ie: RuntimeException::class
* @return callable|ErrorHandler
*/
public function getErrorHandler(string $type)
{
if (isset($this->handlers[$type])) {
return $this->callableResolver->resolve($this->handlers[$type]);
}
if (isset($this->subClassHandlers[$type])) {
return $this->callableResolver->resolve($this->subClassHandlers[$type]);
}
foreach ($this->subClassHandlers as $class => $handler) {
if (is_subclass_of($type, $class)) {
return $this->callableResolver->resolve($handler);
}
}
return $this->getDefaultErrorHandler();
}
/**
* Get default error handler
*
* @return ErrorHandler|callable
*/
public function getDefaultErrorHandler()
{
if ($this->defaultErrorHandler === null) {
$this->defaultErrorHandler = new ErrorHandler(
$this->callableResolver,
$this->responseFactory,
$this->logger
);
}
return $this->callableResolver->resolve($this->defaultErrorHandler);
}
/**
* Set callable as the default Slim application error handler.
*
* The callable signature MUST match the ErrorHandlerInterface
*
* @see \Slim\Interfaces\ErrorHandlerInterface
*
* 1. Instance of \Psr\Http\Message\ServerRequestInterface
* 2. Instance of \Throwable
* 3. Boolean $displayErrorDetails
* 4. Boolean $logErrors
* 5. Boolean $logErrorDetails
*
* The callable MUST return an instance of
* \Psr\Http\Message\ResponseInterface.
*
* @param string|callable|ErrorHandler $handler
*/
public function setDefaultErrorHandler($handler): self
{
$this->defaultErrorHandler = $handler;
return $this;
}
/**
* Set callable to handle scenarios where an error
* occurs when processing the current request.
*
* The callable signature MUST match the ErrorHandlerInterface
*
* Pass true to $handleSubclasses to make the handler handle all subclasses of
* the type as well. Pass an array of classes to make the same function handle multiple exceptions.
*
* @see \Slim\Interfaces\ErrorHandlerInterface
*
* 1. Instance of \Psr\Http\Message\ServerRequestInterface
* 2. Instance of \Throwable
* 3. Boolean $displayErrorDetails
* 4. Boolean $logErrors
* 5. Boolean $logErrorDetails
*
* The callable MUST return an instance of
* \Psr\Http\Message\ResponseInterface.
*
* @param string|string[] $typeOrTypes Exception/Throwable name.
* ie: RuntimeException::class or an array of classes
* ie: [HttpNotFoundException::class, HttpMethodNotAllowedException::class]
* @param string|callable|ErrorHandlerInterface $handler
*/
public function setErrorHandler($typeOrTypes, $handler, bool $handleSubclasses = false): self
{
if (is_array($typeOrTypes)) {
foreach ($typeOrTypes as $type) {
$this->addErrorHandler($type, $handler, $handleSubclasses);
}
} else {
$this->addErrorHandler($typeOrTypes, $handler, $handleSubclasses);
}
return $this;
}
/**
* Used internally to avoid code repetition when passing multiple exceptions to setErrorHandler().
* @param string|callable|ErrorHandlerInterface $handler
*/
private function addErrorHandler(string $type, $handler, bool $handleSubclasses): void
{
if ($handleSubclasses) {
$this->subClassHandlers[$type] = $handler;
} else {
$this->handlers[$type] = $handler;
}
}
}
Slim/Middleware/ContentLengthMiddleware.php 0000644 00000001613 15227044554 0015021 0 ustar 00 handle($request);
// Add Content-Length header if not already added
$size = $response->getBody()->getSize();
if ($size !== null && !$response->hasHeader('Content-Length')) {
$response = $response->withHeader('Content-Length', (string) $size);
}
return $response;
}
}
Slim/Routing/RouteContext.php 0000644 00000004556 15227044554 0012275 0 ustar 00 getAttribute(self::ROUTE);
$routeParser = $serverRequest->getAttribute(self::ROUTE_PARSER);
$routingResults = $serverRequest->getAttribute(self::ROUTING_RESULTS);
$basePath = $serverRequest->getAttribute(self::BASE_PATH);
if ($routeParser === null || $routingResults === null) {
throw new RuntimeException('Cannot create RouteContext before routing has been completed');
}
/** @var RouteInterface|null $route */
/** @var RouteParserInterface $routeParser */
/** @var RoutingResults $routingResults */
/** @var string|null $basePath */
return new self($route, $routeParser, $routingResults, $basePath);
}
private ?RouteInterface $route;
private RouteParserInterface $routeParser;
private RoutingResults $routingResults;
private ?string $basePath;
private function __construct(
?RouteInterface $route,
RouteParserInterface $routeParser,
RoutingResults $routingResults,
?string $basePath = null
) {
$this->route = $route;
$this->routeParser = $routeParser;
$this->routingResults = $routingResults;
$this->basePath = $basePath;
}
public function getRoute(): ?RouteInterface
{
return $this->route;
}
public function getRouteParser(): RouteParserInterface
{
return $this->routeParser;
}
public function getRoutingResults(): RoutingResults
{
return $this->routingResults;
}
public function getBasePath(): string
{
if ($this->basePath === null) {
throw new RuntimeException('No base path defined.');
}
return $this->basePath;
}
}
Slim/Routing/RouteGroup.php 0000644 00000004737 15227044554 0011746 0 ustar 00 pattern = $pattern;
$this->callable = $callable;
$this->callableResolver = $callableResolver;
$this->routeCollectorProxy = $routeCollectorProxy;
}
/**
* {@inheritdoc}
*/
public function collectRoutes(): RouteGroupInterface
{
if ($this->callableResolver instanceof AdvancedCallableResolverInterface) {
$callable = $this->callableResolver->resolveRoute($this->callable);
} else {
$callable = $this->callableResolver->resolve($this->callable);
}
$callable($this->routeCollectorProxy);
return $this;
}
/**
* {@inheritdoc}
*/
public function add($middleware): RouteGroupInterface
{
$this->middleware[] = $middleware;
return $this;
}
/**
* {@inheritdoc}
*/
public function addMiddleware(MiddlewareInterface $middleware): RouteGroupInterface
{
$this->middleware[] = $middleware;
return $this;
}
/**
* {@inheritdoc}
*/
public function appendMiddlewareToDispatcher(MiddlewareDispatcher $dispatcher): RouteGroupInterface
{
foreach ($this->middleware as $middleware) {
$dispatcher->add($middleware);
}
return $this;
}
/**
* {@inheritdoc}
*/
public function getPattern(): string
{
return $this->pattern;
}
}
Slim/Routing/RouteCollectorProxy.php 0000644 00000011026 15227044554 0013627 0 ustar 00 responseFactory = $responseFactory;
$this->callableResolver = $callableResolver;
$this->container = $container;
$this->routeCollector = $routeCollector ?? new RouteCollector($responseFactory, $callableResolver, $container);
$this->groupPattern = $groupPattern;
}
/**
* {@inheritdoc}
*/
public function getResponseFactory(): ResponseFactoryInterface
{
return $this->responseFactory;
}
/**
* {@inheritdoc}
*/
public function getCallableResolver(): CallableResolverInterface
{
return $this->callableResolver;
}
/**
* {@inheritdoc}
*/
public function getContainer(): ?ContainerInterface
{
return $this->container;
}
/**
* {@inheritdoc}
*/
public function getRouteCollector(): RouteCollectorInterface
{
return $this->routeCollector;
}
/**
* {@inheritdoc}
*/
public function getBasePath(): string
{
return $this->routeCollector->getBasePath();
}
/**
* {@inheritdoc}
*/
public function setBasePath(string $basePath): RouteCollectorProxyInterface
{
$this->routeCollector->setBasePath($basePath);
return $this;
}
/**
* {@inheritdoc}
*/
public function get(string $pattern, $callable): RouteInterface
{
return $this->map(['GET'], $pattern, $callable);
}
/**
* {@inheritdoc}
*/
public function post(string $pattern, $callable): RouteInterface
{
return $this->map(['POST'], $pattern, $callable);
}
/**
* {@inheritdoc}
*/
public function put(string $pattern, $callable): RouteInterface
{
return $this->map(['PUT'], $pattern, $callable);
}
/**
* {@inheritdoc}
*/
public function patch(string $pattern, $callable): RouteInterface
{
return $this->map(['PATCH'], $pattern, $callable);
}
/**
* {@inheritdoc}
*/
public function delete(string $pattern, $callable): RouteInterface
{
return $this->map(['DELETE'], $pattern, $callable);
}
/**
* {@inheritdoc}
*/
public function options(string $pattern, $callable): RouteInterface
{
return $this->map(['OPTIONS'], $pattern, $callable);
}
/**
* {@inheritdoc}
*/
public function any(string $pattern, $callable): RouteInterface
{
return $this->map(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'], $pattern, $callable);
}
/**
* {@inheritdoc}
*/
public function map(array $methods, string $pattern, $callable): RouteInterface
{
$pattern = $this->groupPattern . $pattern;
return $this->routeCollector->map($methods, $pattern, $callable);
}
/**
* {@inheritdoc}
*/
public function group(string $pattern, $callable): RouteGroupInterface
{
$pattern = $this->groupPattern . $pattern;
return $this->routeCollector->group($pattern, $callable);
}
/**
* {@inheritdoc}
*/
public function redirect(string $from, $to, int $status = 302): RouteInterface
{
$responseFactory = $this->responseFactory;
$handler = function () use ($to, $status, $responseFactory) {
$response = $responseFactory->createResponse($status);
return $response->withHeader('Location', (string) $to);
};
return $this->get($from, $handler);
}
}
Slim/Routing/Route.php 0000644 00000021503 15227044554 0010717 0 ustar 00
*/
protected array $arguments = [];
/**
* Route arguments parameters
*
* @var string[]
*/
protected array $savedArguments = [];
/**
* Container
*/
protected ?ContainerInterface $container = null;
protected MiddlewareDispatcher $middlewareDispatcher;
/**
* Route callable
*
* @var callable|string
*/
protected $callable;
protected CallableResolverInterface $callableResolver;
protected ResponseFactoryInterface $responseFactory;
/**
* Route pattern
*/
protected string $pattern;
protected bool $groupMiddlewareAppended = false;
/**
* @param string[] $methods The route HTTP methods
* @param string $pattern The route pattern
* @param callable|string $callable The route callable
* @param ResponseFactoryInterface $responseFactory
* @param CallableResolverInterface $callableResolver
* @param ContainerInterface|null $container
* @param InvocationStrategyInterface|null $invocationStrategy
* @param RouteGroupInterface[] $groups The parent route groups
* @param int $identifier The route identifier
*/
public function __construct(
array $methods,
string $pattern,
$callable,
ResponseFactoryInterface $responseFactory,
CallableResolverInterface $callableResolver,
?ContainerInterface $container = null,
?InvocationStrategyInterface $invocationStrategy = null,
array $groups = [],
int $identifier = 0
) {
$this->methods = $methods;
$this->pattern = $pattern;
$this->callable = $callable;
$this->responseFactory = $responseFactory;
$this->callableResolver = $callableResolver;
$this->container = $container;
$this->invocationStrategy = $invocationStrategy ?? new RequestResponse();
$this->groups = $groups;
$this->identifier = 'route' . $identifier;
$this->middlewareDispatcher = new MiddlewareDispatcher($this, $callableResolver, $container);
}
public function getCallableResolver(): CallableResolverInterface
{
return $this->callableResolver;
}
/**
* {@inheritdoc}
*/
public function getInvocationStrategy(): InvocationStrategyInterface
{
return $this->invocationStrategy;
}
/**
* {@inheritdoc}
*/
public function setInvocationStrategy(InvocationStrategyInterface $invocationStrategy): RouteInterface
{
$this->invocationStrategy = $invocationStrategy;
return $this;
}
/**
* {@inheritdoc}
*/
public function getMethods(): array
{
return $this->methods;
}
/**
* {@inheritdoc}
*/
public function getPattern(): string
{
return $this->pattern;
}
/**
* {@inheritdoc}
*/
public function setPattern(string $pattern): RouteInterface
{
$this->pattern = $pattern;
return $this;
}
/**
* {@inheritdoc}
*/
public function getCallable()
{
return $this->callable;
}
/**
* {@inheritdoc}
*/
public function setCallable($callable): RouteInterface
{
$this->callable = $callable;
return $this;
}
/**
* {@inheritdoc}
*/
public function getName(): ?string
{
return $this->name;
}
/**
* {@inheritdoc}
*/
public function setName(string $name): RouteInterface
{
$this->name = $name;
return $this;
}
/**
* {@inheritdoc}
*/
public function getIdentifier(): string
{
return $this->identifier;
}
/**
* {@inheritdoc}
*/
public function getArgument(string $name, ?string $default = null): ?string
{
if (array_key_exists($name, $this->arguments)) {
return $this->arguments[$name];
}
return $default;
}
/**
* {@inheritdoc}
*/
public function getArguments(): array
{
return $this->arguments;
}
/**
* {@inheritdoc}
*/
public function setArguments(array $arguments, bool $includeInSavedArguments = true): RouteInterface
{
if ($includeInSavedArguments) {
$this->savedArguments = $arguments;
}
$this->arguments = $arguments;
return $this;
}
/**
* @return RouteGroupInterface[]
*/
public function getGroups(): array
{
return $this->groups;
}
/**
* {@inheritdoc}
*/
public function add($middleware): RouteInterface
{
$this->middlewareDispatcher->add($middleware);
return $this;
}
/**
* {@inheritdoc}
*/
public function addMiddleware(MiddlewareInterface $middleware): RouteInterface
{
$this->middlewareDispatcher->addMiddleware($middleware);
return $this;
}
/**
* {@inheritdoc}
*/
public function prepare(array $arguments): RouteInterface
{
$this->arguments = array_replace($this->savedArguments, $arguments);
return $this;
}
/**
* {@inheritdoc}
*/
public function setArgument(string $name, string $value, bool $includeInSavedArguments = true): RouteInterface
{
if ($includeInSavedArguments) {
$this->savedArguments[$name] = $value;
}
$this->arguments[$name] = $value;
return $this;
}
/**
* {@inheritdoc}
*/
public function run(ServerRequestInterface $request): ResponseInterface
{
if (!$this->groupMiddlewareAppended) {
$this->appendGroupMiddlewareToRoute();
}
return $this->middlewareDispatcher->handle($request);
}
/**
* @return void
*/
protected function appendGroupMiddlewareToRoute(): void
{
$inner = $this->middlewareDispatcher;
$this->middlewareDispatcher = new MiddlewareDispatcher($inner, $this->callableResolver, $this->container);
/** @var RouteGroupInterface $group */
foreach (array_reverse($this->groups) as $group) {
$group->appendMiddlewareToDispatcher($this->middlewareDispatcher);
}
$this->groupMiddlewareAppended = true;
}
/**
* {@inheritdoc}
*/
public function handle(ServerRequestInterface $request): ResponseInterface
{
if ($this->callableResolver instanceof AdvancedCallableResolverInterface) {
$callable = $this->callableResolver->resolveRoute($this->callable);
} else {
$callable = $this->callableResolver->resolve($this->callable);
}
$strategy = $this->invocationStrategy;
/** @var string[] $strategyImplements */
$strategyImplements = class_implements($strategy);
if (
is_array($callable)
&& $callable[0] instanceof RequestHandlerInterface
&& !in_array(RequestHandlerInvocationStrategyInterface::class, $strategyImplements)
) {
$strategy = new RequestHandler();
}
$response = $this->responseFactory->createResponse();
return $strategy($callable, $request, $response, $this->arguments);
}
}
Slim/Routing/FastRouteDispatcher.php 0000644 00000006153 15227044554 0013550 0 ustar 00 }
*/
public function dispatch($httpMethod, $uri): array
{
$routingResults = $this->routingResults($httpMethod, $uri);
if ($routingResults[0] === self::FOUND) {
return $routingResults;
}
// For HEAD requests, attempt fallback to GET
if ($httpMethod === 'HEAD') {
$routingResults = $this->routingResults('GET', $uri);
if ($routingResults[0] === self::FOUND) {
return $routingResults;
}
}
// If nothing else matches, try fallback routes
$routingResults = $this->routingResults('*', $uri);
if ($routingResults[0] === self::FOUND) {
return $routingResults;
}
if (!empty($this->getAllowedMethods($uri))) {
return [self::METHOD_NOT_ALLOWED, null, []];
}
return [self::NOT_FOUND, null, []];
}
/**
* @param string $httpMethod
* @param string $uri
*
* @return array{int, string|null, array}
*/
private function routingResults(string $httpMethod, string $uri): array
{
if (isset($this->staticRouteMap[$httpMethod][$uri])) {
/** @var string $routeIdentifier */
$routeIdentifier = $this->staticRouteMap[$httpMethod][$uri];
return [self::FOUND, $routeIdentifier, []];
}
if (isset($this->variableRouteData[$httpMethod])) {
/** @var array{0: int, 1?: string, 2?: array} $result */
$result = $this->dispatchVariableRoute($this->variableRouteData[$httpMethod], $uri);
if ($result[0] === self::FOUND) {
/** @var array{int, string, array} $result */
return [self::FOUND, $result[1], $result[2]];
}
}
return [self::NOT_FOUND, null, []];
}
/**
* @param string $uri
*
* @return string[]
*/
public function getAllowedMethods(string $uri): array
{
if (isset($this->allowedMethods[$uri])) {
return $this->allowedMethods[$uri];
}
$allowedMethods = [];
foreach ($this->staticRouteMap as $method => $uriMap) {
if (isset($uriMap[$uri])) {
$allowedMethods[$method] = true;
}
}
foreach ($this->variableRouteData as $method => $routeData) {
$result = $this->dispatchVariableRoute($routeData, $uri);
if ($result[0] === self::FOUND) {
$allowedMethods[$method] = true;
}
}
return $this->allowedMethods[$uri] = array_keys($allowedMethods);
}
}
Slim/Routing/RouteRunner.php 0000644 00000004537 15227044554 0012121 0 ustar 00 routeResolver = $routeResolver;
$this->routeParser = $routeParser;
$this->routeCollectorProxy = $routeCollectorProxy;
}
/**
* This request handler is instantiated automatically in App::__construct()
* It is at the very tip of the middleware queue meaning it will be executed
* last and it detects whether or not routing has been performed in the user
* defined middleware stack. In the event that the user did not perform routing
* it is done here
*
* @throws HttpNotFoundException
* @throws HttpMethodNotAllowedException
*/
public function handle(ServerRequestInterface $request): ResponseInterface
{
// If routing hasn't been done, then do it now so we can dispatch
if ($request->getAttribute(RouteContext::ROUTING_RESULTS) === null) {
$routingMiddleware = new RoutingMiddleware($this->routeResolver, $this->routeParser);
$request = $routingMiddleware->performRouting($request);
}
if ($this->routeCollectorProxy !== null) {
$request = $request->withAttribute(
RouteContext::BASE_PATH,
$this->routeCollectorProxy->getBasePath()
);
}
/** @var Route $route */
$route = $request->getAttribute(RouteContext::ROUTE);
return $route->run($request);
}
}
Slim/Routing/RoutingResults.php 0000644 00000004513 15227044554 0012634 0 ustar 00
*/
protected array $routeArguments;
/**
* @param array $routeArguments
*/
public function __construct(
DispatcherInterface $dispatcher,
string $method,
string $uri,
int $routeStatus,
?string $routeIdentifier = null,
array $routeArguments = []
) {
$this->dispatcher = $dispatcher;
$this->method = $method;
$this->uri = $uri;
$this->routeStatus = $routeStatus;
$this->routeIdentifier = $routeIdentifier;
$this->routeArguments = $routeArguments;
}
public function getDispatcher(): DispatcherInterface
{
return $this->dispatcher;
}
public function getMethod(): string
{
return $this->method;
}
public function getUri(): string
{
return $this->uri;
}
public function getRouteStatus(): int
{
return $this->routeStatus;
}
public function getRouteIdentifier(): ?string
{
return $this->routeIdentifier;
}
/**
* @return array
*/
public function getRouteArguments(bool $urlDecode = true): array
{
if (!$urlDecode) {
return $this->routeArguments;
}
$routeArguments = [];
foreach ($this->routeArguments as $key => $value) {
$routeArguments[$key] = rawurldecode($value);
}
return $routeArguments;
}
/**
* @return string[]
*/
public function getAllowedMethods(): array
{
return $this->dispatcher->getAllowedMethods($this->uri);
}
}
Slim/Routing/RouteResolver.php 0000644 00000002750 15227044554 0012444 0 ustar 00 routeCollector = $routeCollector;
$this->dispatcher = $dispatcher ?? new Dispatcher($routeCollector);
}
/**
* @param string $uri Should be $request->getUri()->getPath()
*/
public function computeRoutingResults(string $uri, string $method): RoutingResults
{
$uri = rawurldecode($uri);
if ($uri === '' || $uri[0] !== '/') {
$uri = '/' . $uri;
}
return $this->dispatcher->dispatch($method, $uri);
}
/**
* @throws RuntimeException
*/
public function resolveRoute(string $identifier): RouteInterface
{
return $this->routeCollector->lookupRoute($identifier);
}
}
Slim/Routing/Dispatcher.php 0000644 00000004650 15227044554 0011713 0 ustar 00 routeCollector = $routeCollector;
}
protected function createDispatcher(): FastRouteDispatcher
{
if ($this->dispatcher) {
return $this->dispatcher;
}
$routeDefinitionCallback = function (FastRouteCollector $r): void {
$basePath = $this->routeCollector->getBasePath();
foreach ($this->routeCollector->getRoutes() as $route) {
$r->addRoute($route->getMethods(), $basePath . $route->getPattern(), $route->getIdentifier());
}
};
$cacheFile = $this->routeCollector->getCacheFile();
if ($cacheFile) {
/** @var FastRouteDispatcher $dispatcher */
$dispatcher = \FastRoute\cachedDispatcher($routeDefinitionCallback, [
'dataGenerator' => GroupCountBased::class,
'dispatcher' => FastRouteDispatcher::class,
'routeParser' => new Std(),
'cacheFile' => $cacheFile,
]);
} else {
/** @var FastRouteDispatcher $dispatcher */
$dispatcher = \FastRoute\simpleDispatcher($routeDefinitionCallback, [
'dataGenerator' => GroupCountBased::class,
'dispatcher' => FastRouteDispatcher::class,
'routeParser' => new Std(),
]);
}
$this->dispatcher = $dispatcher;
return $this->dispatcher;
}
/**
* {@inheritdoc}
*/
public function dispatch(string $method, string $uri): RoutingResults
{
$dispatcher = $this->createDispatcher();
$results = $dispatcher->dispatch($method, $uri);
return new RoutingResults($this, $method, $uri, $results[0], $results[1], $results[2]);
}
/**
* {@inheritdoc}
*/
public function getAllowedMethods(string $uri): array
{
$dispatcher = $this->createDispatcher();
return $dispatcher->getAllowedMethods($uri);
}
}
Slim/Routing/RouteParser.php 0000644 00000007502 15227044554 0012077 0 ustar 00 routeCollector = $routeCollector;
$this->routeParser = new Std();
}
/**
* {@inheritdoc}
*/
public function relativeUrlFor(string $routeName, array $data = [], array $queryParams = []): string
{
$route = $this->routeCollector->getNamedRoute($routeName);
$pattern = $route->getPattern();
$segments = [];
$segmentName = '';
/*
* $routes is an associative array of expressions representing a route as multiple segments
* There is an expression for each optional parameter plus one without the optional parameters
* The most specific is last, hence why we reverse the array before iterating over it
*/
$expressions = array_reverse($this->routeParser->parse($pattern));
foreach ($expressions as $expression) {
foreach ($expression as $segment) {
/*
* Each $segment is either a string or an array of strings
* containing optional parameters of an expression
*/
if (is_string($segment)) {
$segments[] = $segment;
continue;
}
/** @var string[] $segment */
/*
* If we don't have a data element for this segment in the provided $data
* we cancel testing to move onto the next expression with a less specific item
*/
if (!array_key_exists($segment[0], $data)) {
$segments = [];
$segmentName = $segment[0];
break;
}
$segments[] = $data[$segment[0]];
}
/*
* If we get to this logic block we have found all the parameters
* for the provided $data which means we don't need to continue testing
* less specific expressions
*/
if (!empty($segments)) {
break;
}
}
if (empty($segments)) {
throw new InvalidArgumentException('Missing data for URL segment: ' . $segmentName);
}
$url = implode('', $segments);
if ($queryParams) {
$url .= '?' . http_build_query($queryParams);
}
return $url;
}
/**
* {@inheritdoc}
*/
public function urlFor(string $routeName, array $data = [], array $queryParams = []): string
{
$basePath = $this->routeCollector->getBasePath();
$url = $this->relativeUrlFor($routeName, $data, $queryParams);
if ($basePath) {
$url = $basePath . $url;
}
return $url;
}
/**
* {@inheritdoc}
*/
public function fullUrlFor(UriInterface $uri, string $routeName, array $data = [], array $queryParams = []): string
{
$path = $this->urlFor($routeName, $data, $queryParams);
$scheme = $uri->getScheme();
$authority = $uri->getAuthority();
$protocol = ($scheme ? $scheme . ':' : '') . ($authority ? '//' . $authority : '');
return $protocol . $path;
}
}
Slim/Routing/RouteCollector.php 0000644 00000016737 15227044554 0012603 0 ustar 00 responseFactory = $responseFactory;
$this->callableResolver = $callableResolver;
$this->container = $container;
$this->defaultInvocationStrategy = $defaultInvocationStrategy ?? new RequestResponse();
$this->routeParser = $routeParser ?? new RouteParser($this);
if ($cacheFile) {
$this->setCacheFile($cacheFile);
}
}
public function getRouteParser(): RouteParserInterface
{
return $this->routeParser;
}
/**
* Get default route invocation strategy
*/
public function getDefaultInvocationStrategy(): InvocationStrategyInterface
{
return $this->defaultInvocationStrategy;
}
public function setDefaultInvocationStrategy(InvocationStrategyInterface $strategy): RouteCollectorInterface
{
$this->defaultInvocationStrategy = $strategy;
return $this;
}
/**
* {@inheritdoc}
*/
public function getCacheFile(): ?string
{
return $this->cacheFile;
}
/**
* {@inheritdoc}
*/
public function setCacheFile(string $cacheFile): RouteCollectorInterface
{
if (file_exists($cacheFile) && !is_readable($cacheFile)) {
throw new RuntimeException(
sprintf('Route collector cache file `%s` is not readable', $cacheFile)
);
}
if (!file_exists($cacheFile) && !is_writable(dirname($cacheFile))) {
throw new RuntimeException(
sprintf('Route collector cache file directory `%s` is not writable', dirname($cacheFile))
);
}
$this->cacheFile = $cacheFile;
return $this;
}
/**
* {@inheritdoc}
*/
public function getBasePath(): string
{
return $this->basePath;
}
/**
* Set the base path used in urlFor()
*/
public function setBasePath(string $basePath): RouteCollectorInterface
{
$this->basePath = $basePath;
return $this;
}
/**
* {@inheritdoc}
*/
public function getRoutes(): array
{
return $this->routes;
}
/**
* {@inheritdoc}
*/
public function removeNamedRoute(string $name): RouteCollectorInterface
{
$route = $this->getNamedRoute($name);
unset($this->routesByName[$route->getName()], $this->routes[$route->getIdentifier()]);
return $this;
}
/**
* {@inheritdoc}
*/
public function getNamedRoute(string $name): RouteInterface
{
if (isset($this->routesByName[$name])) {
$route = $this->routesByName[$name];
if ($route->getName() === $name) {
return $route;
}
unset($this->routesByName[$name]);
}
foreach ($this->routes as $route) {
if ($name === $route->getName()) {
$this->routesByName[$name] = $route;
return $route;
}
}
throw new RuntimeException('Named route does not exist for name: ' . $name);
}
/**
* {@inheritdoc}
*/
public function lookupRoute(string $identifier): RouteInterface
{
if (!isset($this->routes[$identifier])) {
throw new RuntimeException('Route not found, looks like your route cache is stale.');
}
return $this->routes[$identifier];
}
/**
* {@inheritdoc}
*/
public function group(string $pattern, $callable): RouteGroupInterface
{
$routeGroup = $this->createGroup($pattern, $callable);
$this->routeGroups[] = $routeGroup;
$routeGroup->collectRoutes();
array_pop($this->routeGroups);
return $routeGroup;
}
/**
* @param string|callable $callable
*/
protected function createGroup(string $pattern, $callable): RouteGroupInterface
{
$routeCollectorProxy = $this->createProxy($pattern);
return new RouteGroup($pattern, $callable, $this->callableResolver, $routeCollectorProxy);
}
protected function createProxy(string $pattern): RouteCollectorProxyInterface
{
return new RouteCollectorProxy(
$this->responseFactory,
$this->callableResolver,
$this->container,
$this,
$pattern
);
}
/**
* {@inheritdoc}
*/
public function map(array $methods, string $pattern, $handler): RouteInterface
{
$route = $this->createRoute($methods, $pattern, $handler);
$this->routes[$route->getIdentifier()] = $route;
$routeName = $route->getName();
if ($routeName !== null && !isset($this->routesByName[$routeName])) {
$this->routesByName[$routeName] = $route;
}
$this->routeCounter++;
return $route;
}
/**
* @param string[] $methods
* @param callable|string $callable
*/
protected function createRoute(array $methods, string $pattern, $callable): RouteInterface
{
return new Route(
$methods,
$pattern,
$callable,
$this->responseFactory,
$this->callableResolver,
$this->container,
$this->defaultInvocationStrategy,
$this->routeGroups,
$this->routeCounter
);
}
}
Slim/MiddlewareDispatcher.php 0000644 00000021372 15227044554 0012262 0 ustar 00 seedMiddlewareStack($kernel);
$this->callableResolver = $callableResolver;
$this->container = $container;
}
/**
* {@inheritdoc}
*/
public function seedMiddlewareStack(RequestHandlerInterface $kernel): void
{
$this->tip = $kernel;
}
/**
* Invoke the middleware stack
*/
public function handle(ServerRequestInterface $request): ResponseInterface
{
return $this->tip->handle($request);
}
/**
* Add a new middleware to the stack
*
* Middleware are organized as a stack. That means middleware
* that have been added before will be executed after the newly
* added one (last in, first out).
*
* @param MiddlewareInterface|string|callable $middleware
*/
public function add($middleware): MiddlewareDispatcherInterface
{
if ($middleware instanceof MiddlewareInterface) {
return $this->addMiddleware($middleware);
}
if (is_string($middleware)) {
return $this->addDeferred($middleware);
}
if (is_callable($middleware)) {
return $this->addCallable($middleware);
}
/** @phpstan-ignore-next-line */
throw new RuntimeException(
'A middleware must be an object/class name referencing an implementation of ' .
'MiddlewareInterface or a callable with a matching signature.'
);
}
/**
* Add a new middleware to the stack
*
* Middleware are organized as a stack. That means middleware
* that have been added before will be executed after the newly
* added one (last in, first out).
*/
public function addMiddleware(MiddlewareInterface $middleware): MiddlewareDispatcherInterface
{
$next = $this->tip;
$this->tip = new class ($middleware, $next) implements RequestHandlerInterface {
private MiddlewareInterface $middleware;
private RequestHandlerInterface $next;
public function __construct(MiddlewareInterface $middleware, RequestHandlerInterface $next)
{
$this->middleware = $middleware;
$this->next = $next;
}
public function handle(ServerRequestInterface $request): ResponseInterface
{
return $this->middleware->process($request, $this->next);
}
};
return $this;
}
/**
* Add a new middleware by class name
*
* Middleware are organized as a stack. That means middleware
* that have been added before will be executed after the newly
* added one (last in, first out).
*/
public function addDeferred(string $middleware): self
{
$next = $this->tip;
$this->tip = new class (
$middleware,
$next,
$this->container,
$this->callableResolver
) implements RequestHandlerInterface {
private string $middleware;
private RequestHandlerInterface $next;
private ?ContainerInterface $container;
private ?CallableResolverInterface $callableResolver;
public function __construct(
string $middleware,
RequestHandlerInterface $next,
?ContainerInterface $container = null,
?CallableResolverInterface $callableResolver = null
) {
$this->middleware = $middleware;
$this->next = $next;
$this->container = $container;
$this->callableResolver = $callableResolver;
}
public function handle(ServerRequestInterface $request): ResponseInterface
{
if ($this->callableResolver instanceof AdvancedCallableResolverInterface) {
$callable = $this->callableResolver->resolveMiddleware($this->middleware);
return $callable($request, $this->next);
}
$callable = null;
if ($this->callableResolver instanceof CallableResolverInterface) {
try {
$callable = $this->callableResolver->resolve($this->middleware);
} catch (RuntimeException $e) {
// Do Nothing
}
}
if (!$callable) {
$resolved = $this->middleware;
$instance = null;
$method = null;
// Check for Slim callable as `class:method`
if (preg_match(CallableResolver::$callablePattern, $resolved, $matches)) {
$resolved = $matches[1];
$method = $matches[2];
}
if ($this->container && $this->container->has($resolved)) {
$instance = $this->container->get($resolved);
if ($instance instanceof MiddlewareInterface) {
return $instance->process($request, $this->next);
}
} elseif (!function_exists($resolved)) {
if (!class_exists($resolved)) {
throw new RuntimeException(sprintf('Middleware %s does not exist', $resolved));
}
$instance = new $resolved($this->container);
}
if ($instance && $instance instanceof MiddlewareInterface) {
return $instance->process($request, $this->next);
}
$callable = $instance ?? $resolved;
if ($instance && $method) {
$callable = [$instance, $method];
}
if ($this->container && $callable instanceof Closure) {
$callable = $callable->bindTo($this->container);
}
}
if (!is_callable($callable)) {
throw new RuntimeException(
sprintf(
'Middleware %s is not resolvable',
$this->middleware
)
);
}
return $callable($request, $this->next);
}
};
return $this;
}
/**
* Add a (non-standard) callable middleware to the stack
*
* Middleware are organized as a stack. That means middleware
* that have been added before will be executed after the newly
* added one (last in, first out).
*/
public function addCallable(callable $middleware): self
{
$next = $this->tip;
if ($this->container && $middleware instanceof Closure) {
/** @var Closure $middleware */
$middleware = $middleware->bindTo($this->container);
}
$this->tip = new class ($middleware, $next) implements RequestHandlerInterface {
/**
* @var callable
*/
private $middleware;
/**
* @var RequestHandlerInterface
*/
private $next;
public function __construct(callable $middleware, RequestHandlerInterface $next)
{
$this->middleware = $middleware;
$this->next = $next;
}
public function handle(ServerRequestInterface $request): ResponseInterface
{
return ($this->middleware)($request, $this->next);
}
};
return $this;
}
}
Slim/Exception/HttpBadRequestException.php 0000644 00000001110 15227044554 0014676 0 ustar 00 message = $message;
}
parent::__construct($request, $this->message, $this->code, $previous);
}
}
Slim/Exception/HttpNotFoundException.php 0000644 00000001062 15227044554 0014401 0 ustar 00 request = $request;
}
public function getRequest(): ServerRequestInterface
{
return $this->request;
}
public function getTitle(): string
{
return $this->title;
}
public function setTitle(string $title): self
{
$this->title = $title;
return $this;
}
public function getDescription(): string
{
return $this->description;
}
public function setDescription(string $description): self
{
$this->description = $description;
return $this;
}
}
Slim/Exception/HttpInternalServerErrorException.php 0000644 00000001121 15227044554 0016616 0 ustar 00 allowedMethods;
}
/**
* @param string[] $methods
*/
public function setAllowedMethods(array $methods): self
{
$this->allowedMethods = $methods;
$this->message = 'Method not allowed. Must be one of: ' . implode(', ', $methods);
return $this;
}
}
Slim/Exception/HttpUnauthorizedException.php 0000644 00000001034 15227044554 0015325 0 ustar 00 container = $container;
}
/**
* {@inheritdoc}
*/
public function resolve($toResolve): callable
{
$toResolve = $this->prepareToResolve($toResolve);
if (is_callable($toResolve)) {
return $this->bindToContainer($toResolve);
}
$resolved = $toResolve;
if (is_string($toResolve)) {
$resolved = $this->resolveSlimNotation($toResolve);
$resolved[1] ??= '__invoke';
}
$callable = $this->assertCallable($resolved, $toResolve);
return $this->bindToContainer($callable);
}
/**
* {@inheritdoc}
*/
public function resolveRoute($toResolve): callable
{
return $this->resolveByPredicate($toResolve, [$this, 'isRoute'], 'handle');
}
/**
* {@inheritdoc}
*/
public function resolveMiddleware($toResolve): callable
{
return $this->resolveByPredicate($toResolve, [$this, 'isMiddleware'], 'process');
}
/**
* @param string|callable $toResolve
*
* @throws RuntimeException
*/
private function resolveByPredicate($toResolve, callable $predicate, string $defaultMethod): callable
{
$toResolve = $this->prepareToResolve($toResolve);
if (is_callable($toResolve)) {
return $this->bindToContainer($toResolve);
}
$resolved = $toResolve;
if ($predicate($toResolve)) {
$resolved = [$toResolve, $defaultMethod];
}
if (is_string($toResolve)) {
[$instance, $method] = $this->resolveSlimNotation($toResolve);
if ($method === null && $predicate($instance)) {
$method = $defaultMethod;
}
$resolved = [$instance, $method ?? '__invoke'];
}
$callable = $this->assertCallable($resolved, $toResolve);
return $this->bindToContainer($callable);
}
/**
* @param mixed $toResolve
*/
private function isRoute($toResolve): bool
{
return $toResolve instanceof RequestHandlerInterface;
}
/**
* @param mixed $toResolve
*/
private function isMiddleware($toResolve): bool
{
return $toResolve instanceof MiddlewareInterface;
}
/**
* @throws RuntimeException
*
* @return array{object, string|null} [Instance, Method Name]
*/
private function resolveSlimNotation(string $toResolve): array
{
preg_match(CallableResolver::$callablePattern, $toResolve, $matches);
[$class, $method] = $matches ? [$matches[1], $matches[2]] : [$toResolve, null];
/** @var string $class */
/** @var string|null $method */
if ($this->container && $this->container->has($class)) {
$instance = $this->container->get($class);
if (!is_object($instance)) {
throw new RuntimeException(sprintf('%s container entry is not an object', $class));
}
} else {
if (!class_exists($class)) {
if ($method) {
$class .= '::' . $method . '()';
}
throw new RuntimeException(sprintf('Callable %s does not exist', $class));
}
$instance = new $class($this->container);
}
return [$instance, $method];
}
/**
* @param mixed $resolved
* @param mixed $toResolve
*
* @throws RuntimeException
*/
private function assertCallable($resolved, $toResolve): callable
{
if (!is_callable($resolved)) {
if (is_callable($toResolve) || is_object($toResolve) || is_array($toResolve)) {
$formatedToResolve = ($toResolveJson = json_encode($toResolve)) !== false ? $toResolveJson : '';
} else {
$formatedToResolve = is_string($toResolve) ? $toResolve : '';
}
throw new RuntimeException(sprintf('%s is not resolvable', $formatedToResolve));
}
return $resolved;
}
private function bindToContainer(callable $callable): callable
{
if (is_array($callable) && $callable[0] instanceof Closure) {
$callable = $callable[0];
}
if ($this->container && $callable instanceof Closure) {
/** @var Closure $callable */
$callable = $callable->bindTo($this->container);
}
return $callable;
}
/**
* @param string|callable $toResolve
* @return string|callable
*/
private function prepareToResolve($toResolve)
{
if (!is_array($toResolve)) {
return $toResolve;
}
$candidate = $toResolve;
$class = array_shift($candidate);
$method = array_shift($candidate);
if (is_string($class) && is_string($method)) {
return $class . ':' . $method;
}
return $toResolve;
}
}
Slim/Interfaces/RouteCollectorProxyInterface.php 0000644 00000006651 15227044554 0016114 0 ustar 00
*/
public function getArguments(): array;
/**
* Set a route argument
*/
public function setArgument(string $name, string $value): RouteInterface;
/**
* Replace route arguments
*
* @param array $arguments
*/
public function setArguments(array $arguments): self;
/**
* @param MiddlewareInterface|string|callable $middleware
*/
public function add($middleware): self;
public function addMiddleware(MiddlewareInterface $middleware): self;
/**
* Prepare the route for use
*
* @param array $arguments
*/
public function prepare(array $arguments): self;
/**
* Run route
*
* This method traverses the middleware stack, including the route's callable
* and captures the resultant HTTP response object. It then sends the response
* back to the Application.
*/
public function run(ServerRequestInterface $request): ResponseInterface;
}
Slim/Interfaces/ServerRequestCreatorInterface.php 0000644 00000000555 15227044554 0016241 0 ustar 00 $routeArguments The route's placeholder arguments
*
* @return ResponseInterface The response from the callable.
*/
public function __invoke(
callable $callable,
ServerRequestInterface $request,
ResponseInterface $response,
array $routeArguments
): ResponseInterface;
}
Slim/Interfaces/ErrorHandlerInterface.php 0000644 00000001047 15227044554 0014466 0 ustar 00 getPath()
*/
public function computeRoutingResults(string $uri, string $method): RoutingResults;
public function resolveRoute(string $identifier): RouteInterface;
}
Slim/Interfaces/RouteCollectorInterface.php 0000644 00000004741 15227044554 0015050 0 ustar 00 $data Named argument replacement data
* @param array $queryParams Optional query string parameters
*
* @throws RuntimeException If named route does not exist
* @throws InvalidArgumentException If required data not provided
*/
public function relativeUrlFor(string $routeName, array $data = [], array $queryParams = []): string;
/**
* Build the path for a named route including the base path
*
* @param string $routeName Route name
* @param array $data Named argument replacement data
* @param array $queryParams Optional query string parameters
*
* @throws RuntimeException If named route does not exist
* @throws InvalidArgumentException If required data not provided
*/
public function urlFor(string $routeName, array $data = [], array $queryParams = []): string;
/**
* Get fully qualified URL for named route
*
* @param UriInterface $uri
* @param string $routeName Route name
* @param array $data Named argument replacement data
* @param array $queryParams Optional query string parameters
*/
public function fullUrlFor(UriInterface $uri, string $routeName, array $data = [], array $queryParams = []): string;
}
Slim/Interfaces/Psr17FactoryInterface.php 0000644 00000002323 15227044554 0014341 0 ustar 00