@@ -103,6 +103,9 @@ class Form extends Container implements Nette\HtmlStringable
103103 /** @var bool */
104104 protected $ crossOrigin = false ;
105105
106+ /** @var Nette\Http\IRequest */
107+ private static $ defaultHttpRequest ;
108+
106109 /** @var mixed or null meaning: not detected yet */
107110 private $ submittedBy ;
108111
@@ -666,6 +669,32 @@ public function getToggles(): array
666669 /********************* backend ****************d*g**/
667670
668671
672+ /**
673+ * Initialize standalone forms.
674+ */
675+ public static function initialize (bool $ reinit = false ): void
676+ {
677+ if ($ reinit ) {
678+ self ::$ defaultHttpRequest = null ;
679+ return ;
680+ } elseif (self ::$ defaultHttpRequest ) {
681+ return ;
682+ }
683+
684+ self ::$ defaultHttpRequest = (new Nette \Http \RequestFactory )->fromGlobals ();
685+
686+ if (PHP_SAPI !== 'cli ' ) {
687+ if (headers_sent ($ file , $ line )) {
688+ throw new Nette \InvalidStateException (
689+ 'Create a form or call Nette\Forms\Form::initialize() before the headers are sent to initialize CSRF protection. '
690+ . ($ file ? " (output started at $ file: $ line) " : '' ) . '. '
691+ );
692+ }
693+ Nette \Http \Helpers::initCookie (self ::$ defaultHttpRequest , new Nette \Http \Response );
694+ }
695+ }
696+
697+
669698 /** @internal */
670699 public function setHttpRequest (Nette \Http \IRequest $ request )
671700 {
@@ -676,9 +705,8 @@ public function setHttpRequest(Nette\Http\IRequest $request)
676705 private function getHttpRequest (): Nette \Http \IRequest
677706 {
678707 if (!$ this ->httpRequest ) {
679- $ factory = new Nette \Http \RequestFactory ;
680- $ this ->httpRequest = $ factory ->createHttpRequest ();
681- Nette \Http \Helpers::initCookie ($ this ->httpRequest , new Nette \Http \Response );
708+ self ::initialize ();
709+ $ this ->httpRequest = self ::$ defaultHttpRequest ;
682710 }
683711 return $ this ->httpRequest ;
684712 }
0 commit comments