Skocz do zawartości

Wykonywanie skryptu po załadowaniu strony


korpirkor

Rekomendowane odpowiedzi

Witam ;)

Ciekawi mnie taka rzecz:

Po wysłaniu całej treści dokumentu do użytkownika - Status w przeglądarce: "Zakończono" - Czy skrypt może działać dalej w tle (np. zapisując w cache wygenerowaną stronę)

Pytanie czysto teoretyczne, nie interesują mnie rozwiązania typu cron czy zapisywanie podczas wczytywania strony.

Dzięki, pozdrawiam ;)

Odnośnik do komentarza
Udostępnij na innych stronach

Nie. ale możesz użyć funkcji buforujących https://www.php.net/manual/en/ref.outcontrol.php do "postaborcyjnego" wysyłania danych na standardowe wyjście.

HTTP 200 usługi IT -> Dariusz Janicki | Realizacja serwisów www oraz oprogramowania w PHP / C# / Golang / Node.js / MySQL/ Laravel
Komory normobaryczne - normobaria.tech Wykonawca montażu i instalacji komory normobarii

Odnośnik do komentarza
Udostępnij na innych stronach

Nie. ale możesz użyć funkcji buforujących https://www.php.net/manual/en/ref.outcontrol.php do "postaborcyjnego" wysyłania danych na standardowe wyjście.

Co znaczy nie? Powiedziałbyś, że nie wiesz, a nie mieszasz innym.

Można używając register_shutdown_function(); ponieważ funkcja tak zarejestrowana zostanie wykonana na 100% na koniec skryptu nawet jak wywołasz die() czy exit() czy użytkownik zatrzyma ładowanie strony w przeglądarce więc rejestrujesz jakąś funkcję i gdy chcesz żeby skrypt wysłał już dane do przeglądarki wywołujesz die(), a zarejestrowana funkcja działa w tle na serwerze.

np.

<?php

register_shutdown_function('foo');

function foo() {
//kod który będzie wykonany na koniec skryptu w tle 
}

echo 'Bla bla';

echo 'Bla bla';

die(); //wywołujesz die(); przeglądarka to ładuje to co echowałeś i kończy, a funkcja foo() działa w tle na serwerze (nawet jeśli dasz jej roboty na cały dzień)
?>

Odnośnik do komentarza
Udostępnij na innych stronach

Co znaczy nie? Powiedziałbyś, że nie wiesz, a nie mieszasz innym.
To jak "geniuszu" :) wytłumaczysz oczekiwanie na wysłanie danych do przeglądarki z tego kodu. Chyba, że nie rozumiesz o czym jest ten topic ;) :

<?php
// test2.php
register_shutdown_function('foo');
function foo()
{
//Jakaś operacja -kod do wykonania po wysłany danych do klienta 
for($jj = 0; $jj < 10000; $jj++)
{
	for($ii = 0; $ii < 2000; $ii++)
	{
		rand(1,111111);
	}
}
echo '<br />Z foo:'.time();
}
echo 'Start: '.time().' <br />';
echo 'Koniec: '.time();
// to samo z  z exit; 
?>

Online: https://hot.net.pl/test/test2.php

Sławek, a tu z Twojego sposobu:

<?php
// test.php
ob_start();
echo 'Start: '.time().' <br />';

echo 'Bla bla<br />';

header("Content-Length: ".ob_get_length());
$dane =  ob_get_contents();
ob_end_clean();
echo $dane;


//Jakaś operacja -kod do wykonania po wysłany danych do klienta 
for($jj = 0; $jj < 10000; $jj++)
{
for($ii = 0; $ii < 2000; $ii++)
{
	rand(1,111111);
}
}

echo 'Koniec: '.time();

?>

Online: https://hot.net.pl/test/test.php Gdyby działo tak jak chodzi autorowi topicka nie czekalibyśmy na wykonanie kodu z pętli. Zresztą tak samo się czeka jak nie ma na koncu za pętlą echo 'Koniec: '.time();

HTTP 200 usługi IT -> Dariusz Janicki | Realizacja serwisów www oraz oprogramowania w PHP / C# / Golang / Node.js / MySQL/ Laravel
Komory normobaryczne - normobaria.tech Wykonawca montażu i instalacji komory normobarii

Odnośnik do komentarza
Udostępnij na innych stronach

@Awzan:

Można używając register_shutdown_function();
W starych wersjach php. Za manualem:
The shutdown functions are now called as a part of the request. In earlier versions (<4.1.0) under Apache, the registered shutdown functions were called after the request has been completed (including sending any output buffers), so it was not possible to send output to the browser using echo() or print(), or retrieve the contents of any output buffers using ob_get_contents(). Headers were also always already sent.

Jak testowałem to też nigdzie to nie działało. Wersja 4 już chyba z kilka lat nie jest używana.

@Mion: jasne, że działa, tylko jak zwykle to nie takie proste jak się wydaje.

1. Jak masz mniej niż 1024 bajtów to musisz zrobić padding dla niektórych browserów.

2. Flush i header: connection-close to już zależy od konfiguracji PHP. Niekiedy ponoć działa bez ale lepiej dodać.

Poza tym jesteś jedną z osób które rozumieją HTML/PHP najlepiej na forum, tyle się nagadałem o tym, że do przeglądarki wysłany jest HTML a nie XHTML a ty dalej powielasz błędy z gazet i używasz XHTML-owy shorttag __<br />__ :)

Link do testu: https://r2.to.pl/bkprocess.php - tylko jeden użytkownik może uruchamiać skrypt jednocześnie - żeby testy nie zablokowały serwera :jezyk1:

Poza tym w background() najlepiej zrobić ob_start() i ob_end_clean() na końcu, żebyśmy za szybko przypadkiem jakiegoś echo nie zrobili bo browser sobie może pomyśleć, że nam się pomylił content-length i nie zakończy połączenia.

<?
ignore_user_abort(true);
ob_start();

if (@file_get_contents('xlock') == '1')
die('zablokowany');
file_put_contents("xlock", 1);

// [....] - tu właściwy skrypt
echo 'costam';
finish(); // wysłanie do przeglądarki


background(); // przetwarzanie w tle


function finish()
{
$data = ob_get_contents();
$_ldata = strlen($data);
if ($_ldata<1024)
{
	$data .= str_pad('', 1024-$_ldata, ' ');
	$_ldata = strlen($data);
}
ob_end_clean();

header("HTTP/1.1 200 OK");  
header("Content-Length: {$_ldata}");
header("Connection: Close");
echo $data;
flush();
}

function background()
{
sleep(10);
echo "NIE DZIALA!";

file_put_contents("xlock", 0);
}

?>

Odnośnik do komentarza
Udostępnij na innych stronach

Jasne, że nie jest (fakt, zły przykład na blokowanie).

Co do flock - to z doświadczenia wiem, że jest tak bardzo atomowy, że nie nadaje się do niczego i prędzej czy później będziesz miał uszkodzone dane jeśli w serwisie z większą ilością odwiedzin z niego korzystasz :chatownik:

Co do samych lock-ów/critical sections... to dość dobrze nadaje się do tego GET_LOCK() z mysql. Niestety jest limit 1 lock / proces.

Odnośnik do komentarza
Udostępnij na innych stronach

Slawek - to chyba źle z flocków korzystasz. I przy okazji - tutaj pojawia się słabość PHP - brak wsparcia dla synchronizacji wątków (to co np. mamy w javie).

Na osłodę - do takich synchronizacji w PHP możesz też użyć np. semaforów lub memcached jeżeli z flock Ci nie wychodzi. Jednak z memcached do tego celu, to trzeba to umiejętnie napisać plus teoretycznie nie jest to w 100% stabilne z uwagi na to, że memcached może usunąć zasób aby zrobić miejsce na inne zasoby. Jednak czas synchronizacji z reguły trwa bardzo krótko więc nie powinno to stanowić problemu.

Odnośnik do komentarza
Udostępnij na innych stronach

Tu nie ma problemu złego wykorzystania flock-ów, nawet jeśli używasz teoretycznie bezpiecznego trybu fopen(..., 'a') zamiast fopen(..., 'w/w+') to wystarczy, że podczas zapisu zrestartujesz serwer i tracisz dane. Tryb a jest trochę bezpieczniejszy, możesz co najwyżej mieć błędy w nowo zapisywanych danych.

Najlepiej byłoby odczytać całą zawartość pliku, zmodyfikować kopię a potem zrobić rename. Niestety wiadomo, jak w większości wypadków to będzie nieefektywne. Ale wtedy taki zapis jest atomowy. Tzn. albo masz nową zawartość albo starą, ale zawsze poprawną (obojętnie co by się nie działo). Dlatego model fopen/flock/fwrite jest nieatomowy. Jak coś padnie to możesz stracić wszystkie dane bo plik będzie niepoprawny, jak zapisujesz do bazy danych ACID - tracisz co najwyżej zmiany.

Z doświadczenia wiem (pomijając czy flock jest atomic czy nie), że nawet jeśli zrobisz fopen a, potem flock, sprawdzisz czy plik jest zablokowany i dopiero potem zaczniesz zapisywać - to dane niekiedy i tak lubią się "gubić". Problem rozwiązałoby pewnie takie coś jak Transactional NTFS microsoftu :D

Odnośnik do komentarza
Udostępnij na innych stronach

Tu nie ma problemu złego wykorzystania flock-ów, nawet jeśli używasz teoretycznie bezpiecznego trybu fopen(..., 'a') zamiast fopen(..., 'w/w+') to wystarczy, że podczas zapisu zrestartujesz serwer i tracisz dane. Tryb a jest trochę bezpieczniejszy, możesz co najwyżej mieć błędy w nowo zapisywanych danych.

Problem z restartem i utratą danych to trochę osobna sprawa, natomiast generalnie lepiej jest kiedy do synchronizacji zapisu nie robisz flocka na pliku na którym działasz tylko zakładasz flocka na pusty pomocniczy plik.

Odnośnik do komentarza
Udostępnij na innych stronach

Zarchiwizowany

Ten temat przebywa obecnie w archiwum. Dodawanie nowych odpowiedzi zostało zablokowane.

  • Ostatnio przeglądający   0 użytkowników

    • Brak zarejestrowanych użytkowników przeglądających tę stronę.
×
×
  • Dodaj nową pozycję...

Powiadomienie o plikach cookie

Umieściliśmy na Twoim urządzeniu pliki cookie, aby pomóc Ci usprawnić przeglądanie strony. Możesz dostosować ustawienia plików cookie, w przeciwnym wypadku zakładamy, że wyrażasz na to zgodę. Warunki użytkowania Polityka prywatności