@@ -25,9 +25,13 @@ class Router
2525 public const BEFORE = -1 ; // before
2626 public const AFTER = 1 ; // after
2727
28+ public const ROUTE = 0 ;
29+
30+ public const LINK = 1 ;
31+
2832 public const SUPPORTED_METHODS = [
2933 'GET ' , 'POST ' , 'PUT ' , 'DELETE ' , 'HEAD ' , 'PATCH ' , 'OPTIONS ' ,
30- 'ANY ' ,
34+ 'ANY ' , ' LINK '
3135 ];
3236
3337 /** @var array */
@@ -77,6 +81,8 @@ class Router
7781 '{date[0-9]?} ' => '([0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])) ' ,
7882 ':locale ' => '([A-Za-z]{2}|[A-Za-z]{2}[\_\-]{1}[A-Za-z]{2}) ' ,
7983 '{locale} ' => '([A-Za-z]{2}|[A-Za-z]{2}[\_\-]{1}[A-Za-z]{2}) ' ,
84+ ':everything ' => '(.*) ' ,
85+ '{everything} ' => '(.*) ' ,
8086 ];
8187
8288 /** @var RequestInterface */
@@ -90,6 +96,7 @@ class Router
9096
9197 protected $ container ;
9298
99+ /** @var int */
93100 protected $ id = 0 ;
94101
95102 /** @var array */
@@ -268,6 +275,19 @@ public function register($methods, string $path, $execute, array $options = []):
268275 return $ this ;
269276 }
270277
278+
279+ public function link (string $ link , string $ source , array $ options = []): self
280+ {
281+ if (!\file_exists ($ source )) {
282+ throw new InvalidArgumentException ("\$source can be directory or file. " );
283+ }
284+ if (\is_dir ($ source )) {
285+ $ link = \rtrim ($ link , '/ ' ) . '/(.*) ' ;
286+ }
287+
288+ return $ this ->register (['LINK ' ], $ link , $ source , $ options );
289+ }
290+
271291 /**
272292 * @see Router::register()
273293 * @param string|string[] $methods
@@ -677,23 +697,7 @@ public function dispatch(): ResponseInterface
677697 $ hasRoute = isset ($ this ->current_route ) && !empty ($ this ->current_route );
678698
679699 if ($ hasRoute === FALSE ){
680- $ this ->response = $ this ->response ->withStatus (404 );
681- if (empty ($ this ->error_404 ['execute ' ])){
682- throw new PageNotFoundException ('Error 404 : Page Not Found ' );
683- }
684- \define ('INITPHP_ROUTER_CURRENT_ARGUMENTS ' , $ this ->error_404 ['options ' ]['arguments ' ]);
685- if (\is_callable ($ this ->error_404 ['execute ' ])){
686- \define ('INITPHP_ROUTER_CURRENT_CONTROLLER ' , '__CALLABLE__ ' );
687- \define ('INITPHP_ROUTER_CURRENT_METHOD ' , '' );
688- return $ this ->response = $ this ->execute ($ this ->error_404 ['execute ' ], $ this ->error_404 ['options ' ]['arguments ' ]);
689- }
690- $ parse = $ this ->getControllerMethod ($ this ->error_404 ['execute ' ], $ this ->error_404 ['options ' ]);
691- $ parse ['controller ' ] = $ this ->controllerFind ($ parse ['controller ' ]);
692- $ controller = $ this ->getClassContainer (new \ReflectionClass ($ parse ['controller ' ]));
693- \define ('INITPHP_ROUTER_CURRENT_CONTROLLER ' , \get_class ($ controller ));
694- \define ('INITPHP_ROUTER_CURRENT_METHOD ' , $ parse ['method ' ]);
695-
696- return $ this ->response = $ this ->execute ([$ controller , $ parse ['method ' ]], $ this ->error_404 ['options ' ]['arguments ' ]);
700+ return $ this ->notFound ();
697701 }
698702
699703 $ route = $ this ->current_route ;
@@ -723,27 +727,30 @@ public function dispatch(): ResponseInterface
723727 if ($ responseStatusCode < 200 || $ responseStatusCode > 299 ){
724728 return $ this ->response ;
725729 }
726-
727- if (\is_callable ($ route ['execute ' ])){
728- \define ('INITPHP_ROUTER_CURRENT_CONTROLLER ' , '__CALLABLE__ ' );
729- \define ('INITPHP_ROUTER_CURRENT_METHOD ' , '' );
730- $ this ->response = $ this ->execute ($ route ['execute ' ], $ arguments );
731- }else {
732- $ parse = $ this ->getControllerMethod ($ route ['execute ' ], $ route ['options ' ]);
733- $ parse ['controller ' ] = $ this ->controllerFind ($ parse ['controller ' ]);
734- $ reflection = new \ReflectionClass ($ parse ['controller ' ]);
735- $ controller = $ this ->getClassContainer ($ reflection );
736- $ this ->middleware_handle ($ this ->controller_middlewares_property ($ controller , $ parse ['method ' ], self ::BEFORE ), $ arguments , self ::BEFORE );
737- \define ('INITPHP_ROUTER_CURRENT_CONTROLLER ' , \get_class ($ controller ));
738- \define ('INITPHP_ROUTER_CURRENT_METHOD ' , $ parse ['method ' ]);
739- $ responseStatusCode = (int )$ this ->response ->getStatusCode ();
740- if ($ responseStatusCode < 200 || $ responseStatusCode > 299 ){
741- return $ this ->response ;
742- }
743- $ this ->response = $ this ->execute ([$ controller , $ parse ['method ' ]], $ arguments );
744- $ after_middleware = $ this ->controller_middlewares_property ($ controller , $ parse ['method ' ], self ::AFTER );
745- if (!empty ($ after_middleware )){
746- $ filters ['after ' ] = \array_merge ($ filters ['after ' ], $ after_middleware );
730+ if ($ route ['methods ' ] === ['LINK ' ]) {
731+ return $ this ->execute ($ route ['execute ' ], $ arguments , self ::LINK );
732+ } else {
733+ if (\is_callable ($ route ['execute ' ])){
734+ \define ('INITPHP_ROUTER_CURRENT_CONTROLLER ' , '__CALLABLE__ ' );
735+ \define ('INITPHP_ROUTER_CURRENT_METHOD ' , '' );
736+ $ this ->response = $ this ->execute ($ route ['execute ' ], $ arguments );
737+ }else {
738+ $ parse = $ this ->getControllerMethod ($ route ['execute ' ], $ route ['options ' ]);
739+ $ parse ['controller ' ] = $ this ->controllerFind ($ parse ['controller ' ]);
740+ $ reflection = new \ReflectionClass ($ parse ['controller ' ]);
741+ $ controller = $ this ->getClassContainer ($ reflection );
742+ $ this ->middleware_handle ($ this ->controller_middlewares_property ($ controller , $ parse ['method ' ], self ::BEFORE ), $ arguments , self ::BEFORE );
743+ \define ('INITPHP_ROUTER_CURRENT_CONTROLLER ' , \get_class ($ controller ));
744+ \define ('INITPHP_ROUTER_CURRENT_METHOD ' , $ parse ['method ' ]);
745+ $ responseStatusCode = (int )$ this ->response ->getStatusCode ();
746+ if ($ responseStatusCode < 200 || $ responseStatusCode > 299 ){
747+ return $ this ->response ;
748+ }
749+ $ this ->response = $ this ->execute ([$ controller , $ parse ['method ' ]], $ arguments );
750+ $ after_middleware = $ this ->controller_middlewares_property ($ controller , $ parse ['method ' ], self ::AFTER );
751+ if (!empty ($ after_middleware )){
752+ $ filters ['after ' ] = \array_merge ($ filters ['after ' ], $ after_middleware );
753+ }
747754 }
748755 }
749756
@@ -762,7 +769,7 @@ public function resolve(string $method, string $current_url): ?array
762769 $ this ->current_url = $ current_url ;
763770 $ this ->current_method = $ method = \strtoupper ($ method );
764771
765- $ routes = \array_unique (\array_merge ($ this ->methodIds ['ANY ' ], $ this ->methodIds [$ method ]));
772+ $ routes = \array_unique (\array_merge ($ this ->methodIds ['LINK ' ], $ this -> methodIds [ ' ANY ' ], $ this ->methodIds [$ method ]));
766773 $ patterns = $ this ->getPatterns ();
767774 $ matches = [];
768775 foreach ($ routes as $ id ) {
@@ -779,6 +786,9 @@ public function resolve(string $method, string $current_url): ?array
779786 if (\preg_match ('#^ ' . $ path . '$# ' , $ this ->current_url , $ arguments )){
780787 \array_shift ($ arguments );
781788 $ route ['arguments ' ] = $ arguments ;
789+ if ($ route ['methods ' ] === ['LINK ' ]) {
790+ return $ this ->current_method = $ route ;
791+ }
782792 $ matches_size = \strlen ($ route ['path ' ]);
783793 if (\is_array ($ arguments ) && !empty ($ arguments )){
784794 $ matches_size += (\count ($ arguments ) * 25 );
@@ -938,8 +948,25 @@ private function middleware_handle(array $filters, $arguments, int $pos): void
938948 }
939949 }
940950
941- private function execute ($ execute , array $ arguments ): ResponseInterface
951+ private function execute ($ execute , array $ arguments, int $ type = self :: ROUTE ): ResponseInterface
942952 {
953+ if ($ type === self ::LINK ) {
954+ $ path = $ execute
955+ . ($ arguments [0 ] ?? '' );
956+ if (\is_file ($ path )) {
957+ if (($ size = \filesize ($ path )) < 2097152 ) {
958+ $ this ->response ->getBody ()->write (@\file_get_contents ($ path ));
959+ return $ this ->response = $ this ->response ->withHeader ('Content-Type ' , \mime_content_type ($ path ))
960+ ->withHeader ('Content-Length ' , $ size );
961+ } else {
962+ @header ("Content-Type: " . \mime_content_type ($ path ) . "; " );
963+ @header ("Content-Length: " . $ size . "; " );
964+ readfile ($ path );
965+ exit ;
966+ }
967+ }
968+ return $ this ->notFound ();
969+ }
943970 $ reflection = is_array ($ execute ) ? new \ReflectionMethod ($ execute [0 ], $ execute [1 ]) : new \ReflectionFunction ($ execute );
944971 ob_start (function ($ tmp ) {
945972 $ this ->content .= $ tmp ;
@@ -1287,4 +1314,35 @@ private function confirm_ip_addresses($ip): array
12871314 return $ res ;
12881315 }
12891316
1317+ private function notFound (): ResponseInterface
1318+ {
1319+ $ this ->response = $ this ->response ->withStatus (404 );
1320+ if (empty ($ this ->error_404 ['execute ' ])){
1321+ throw new PageNotFoundException ('Error 404 : Page Not Found ' );
1322+ }
1323+ if (!\defined ("INITPHP_ROUTER_CURRENT_ARGUMENTS " )) {
1324+ \define ('INITPHP_ROUTER_CURRENT_ARGUMENTS ' , $ this ->error_404 ['options ' ]['arguments ' ]);
1325+ }
1326+ if (\is_callable ($ this ->error_404 ['execute ' ])){
1327+ if (!\defined ("INITPHP_ROUTER_CURRENT_CONTROLLER " )) {
1328+ \define ('INITPHP_ROUTER_CURRENT_CONTROLLER ' , '__CALLABLE__ ' );
1329+ }
1330+ if (!\defined ("INITPHP_ROUTER_CURRENT_METHOD " )) {
1331+ \define ('INITPHP_ROUTER_CURRENT_METHOD ' , '' );
1332+ }
1333+ return $ this ->response = $ this ->execute ($ this ->error_404 ['execute ' ], $ this ->error_404 ['options ' ]['arguments ' ]);
1334+ }
1335+ $ parse = $ this ->getControllerMethod ($ this ->error_404 ['execute ' ], $ this ->error_404 ['options ' ]);
1336+ $ parse ['controller ' ] = $ this ->controllerFind ($ parse ['controller ' ]);
1337+ $ controller = $ this ->getClassContainer (new \ReflectionClass ($ parse ['controller ' ]));
1338+ if (!\defined ("INITPHP_ROUTER_CURRENT_CONTROLLER " )) {
1339+ \define ('INITPHP_ROUTER_CURRENT_CONTROLLER ' , \get_class ($ controller ));
1340+ }
1341+ if (!\defined ("INITPHP_ROUTER_CURRENT_METHOD " )) {
1342+ \define ('INITPHP_ROUTER_CURRENT_METHOD ' , $ parse ['method ' ]);
1343+ }
1344+
1345+ return $ this ->response = $ this ->execute ([$ controller , $ parse ['method ' ]], $ this ->error_404 ['options ' ]['arguments ' ]);
1346+ }
1347+
12901348}
0 commit comments