9999define ('TRANSLATION_CONSTANT_ESCAPE ' , '%% ' );
100100
101101
102+ /** Path used in dev mode for sending updates to client */
103+ define ('DEV_SSE_URI ' , '.LUP ' );
104+
105+ /** Interval in milliseconds for checking file system for changes */
106+ define ('DEV_CHECK_FILE_CHANGES ' , 500 );
107+
108+
102109// ---------------------------------------------------------------------------------------
103110// INTERAL PROCESSING OF REQUESTS
104111// ---------------------------------------------------------------------------------------
@@ -193,13 +200,95 @@ function toSupportedLanguage($code){
193200$ langLen = strlen (LANGUAGE_CODE );
194201define ('REQUEST ' , ($ fullRequestLen < $ langLen || strtolower (substr (FULL_REQUEST , 0 , $ langLen )) != $ lang ) ? FULL_REQUEST : substr (FULL_REQUEST , $ langLen +1 ));
195202
203+ /** Load environment variables */
204+ function reloadEnv (){
205+ unset($ _ENV );
206+ if (($ handle = fopen (ENVIRONMENT_FILE , "r " ))){
207+ while (($ line = fgets ($ handle )) !== false ){
208+ $ idx = strpos ($ line , "= " );
209+ if ($ idx < 0 ) continue ;
210+ $ k = trim (substr ($ line , 0 , $ idx ));
211+ if (empty ($ k ) || $ k [0 ] === '# ' ) continue ;
212+ $ v = trim (substr ($ line , $ idx +1 ));
213+ $ _ENV [$ k ] = $ v ;
214+ putenv ($ k .'= ' .$ v );
215+ }
216+ fclose ($ handle );
217+ }
218+ }
219+
220+ /** Returns true if server runs in development mode, otherwise false */
221+ function isDevMode (){
222+ return isset ($ _ENV ['DEV ' ]) && (empty ($ _ENV ['DEV ' ]) || $ _ENV ['DEV ' ] === '1 ' || strtolower ($ _ENV ['DEV ' ]) === 'true ' );
223+ }
224+
196225/**
197226 * Function takes the path of a file from framework root, sets appropiate headers,
198227 * echos the contents of the file and exits the execution of the script.
199228 * If file does not exist the NOT_FOUND_PAGE will be used if defined otherwise responds with 404 error.
200229 * @param String $file Path to the file
201230 */
202231function respondWithFile ($ file , $ isAlreadyNotFound =false , $ isInsideStatics =false , $ prefix =false ){
232+
233+ // dev mode SSE
234+ if ($ file === VIEWS .DEV_SSE_URI ){
235+ reloadEnv ();
236+ if (isDevMode ()){
237+ header ('Content-Type: text/event-stream ' );
238+ header ('Cache-Control: no-cache ' );
239+ header ('Connection: Keep-Alive ' );
240+
241+ function initFiles ($ files =array (), $ prefix ='' ){
242+ $ result = array ();
243+ foreach ($ files as $ file ){
244+ if ($ file === '. ' || $ file === '.. ' ) continue ;
245+ $ fullFile = $ prefix .$ file ;
246+ if (is_dir ($ fullFile ))
247+ array_push ($ result , ...initFiles (scandir ($ fullFile ), $ fullFile .'/ ' ));
248+ else
249+ array_push ($ result , $ fullFile .': ' .filemtime ($ fullFile ));
250+ }
251+ return $ result ;
252+ }
253+ $ FILES = initFiles (scandir ('. ' ));
254+ $ FILES_LEN = count ($ FILES );
255+
256+ /** Returns count of found files or -1 if file has changed */
257+ function checkFiles ($ FILES =array (), $ files =array (), $ prefix ='' ){
258+ $ count = 0 ;
259+ foreach ($ files as $ file ){
260+ if ($ file === '. ' || $ file === '.. ' ) continue ;
261+ $ fullFile = $ prefix .$ file ;
262+ if (is_dir ($ fullFile )){
263+ $ found = checkFiles ($ FILES , scandir ($ fullFile ), $ fullFile .'/ ' );
264+ if ($ found === -1 ) return -1 ;
265+ $ count = $ count + $ found ;
266+ } else if (in_array ($ fullFile .': ' .filemtime ($ fullFile ), $ FILES )){
267+ $ count = $ count + 1 ;
268+ } else {
269+ echo $ fullFile .': ' .filemtime ($ fullFile ).'<br /> ' ;
270+ return -1 ;
271+ }
272+ }
273+ return $ count ;
274+ }
275+
276+ while (!connection_aborted ()){
277+ usleep (DEV_CHECK_FILE_CHANGES );
278+ if (checkFiles ($ FILES , scandir ('. ' )) !== $ FILES_LEN ){
279+ echo "event: message \n" ;
280+ echo "data: { \"reload \": true} " ;
281+ echo "\n\n" ;
282+ ob_end_flush ();
283+ flush ();
284+ $ FILES = initFiles (scandir ('. ' ));
285+ $ FILES_LEN = count ($ FILES );
286+ }
287+ }
288+ exit (0 );
289+ }
290+ }
291+
203292 // safety checks
204293 $ realFile = ($ file ? realpath ($ file ) : '' ); $ realRoot = realpath (__DIR__ );
205294 if (!$ file || !file_exists ($ file ) || strlen ($ realFile ) < strlen ($ realRoot ) || !str_starts_with ($ realFile , $ realRoot )){
@@ -249,22 +338,12 @@ function respondWithFile($file, $isAlreadyNotFound=false, $isInsideStatics=false
249338 define ('ROOT ' , BASE .(ROOT_DEPTH != BASE_DEPTH ? '../ ' : '' ));
250339 foreach (scandir (STATICS ) as $ dir ) if (is_dir (STATICS .$ dir )) define (strtoupper ($ dir ), ROOT .$ dir .'/ ' );
251340
252- // Load environment variables
253- if (($ handle = fopen (ENVIRONMENT_FILE , "r " ))){
254- while (($ line = fgets ($ handle )) !== false ){
255- $ idx = strpos ($ line , "= " );
256- if ($ idx < 0 ) continue ;
257- $ k = trim (substr ($ line , 0 , $ idx ));
258- if (empty ($ k ) || $ k [0 ] === '# ' ) continue ;
259- $ v = trim (substr ($ line , $ idx +1 ));
260- $ _ENV [$ k ] = $ v ;
261- putenv ($ k .'= ' .$ v );
262- }
263- fclose ($ handle );
264- }
341+ reloadEnv ();
265342
266343 include ('config.php ' );
267344
345+ $ IS_DEV = isDevMode ();
346+
268347 function replaceVariables ($ str ){
269348 $ val = "" ; $ start = -1 ; $ end = 0 ;
270349 do {
@@ -295,6 +374,12 @@ function replaceVariables($str){
295374 define ('TEXT ' , $ arr );
296375
297376 include ($ file );
377+ if ($ IS_DEV )
378+ foreach (headers_list () as $ header )
379+ if (strpos ($ header , 'text/html ' ) !== false ){
380+ echo '<script type="text/javascript">(function(){const es=new EventSource(" ' .ROOT .DEV_SSE_URI .'");es.addEventListener("message",function(event){console.log(event.data);if(JSON.parse(event.data).reload)window.location.reload(true);});})();</script> ' ;
381+ break ;
382+ }
298383 exit (0 );
299384 }
300385
@@ -312,7 +397,8 @@ function replaceVariables($str){
312397 if (isset (STATICS_CACHE_SECONDS [$ dir ])){
313398 require_once (SCRIPTS .'caching.php ' );
314399 $ cacheSec = STATICS_CACHE_SECONDS [$ dir ];
315- if ($ cacheSec >= 0 ) setCache ($ cacheSec ); else noCache ();
400+ reloadEnv ();
401+ if ($ cacheSec >= 0 && !isDevMode ()) setCache ($ cacheSec ); else noCache ();
316402 }
317403 if ($ dir === _CSS ) include (CSS_COMPONENTS .'css-config.php ' );
318404 if ($ dir === _JS ) include (JS_COMPONENTS .'js-config.php ' );
0 commit comments