Skocz do zawartości
eRIZ

php-fpm i zwracane coś w stylu 404

Polecane posty

Witam. ;)

 

Stawiam obecnie serwer na FreeBSD + nginx + php-fpm.

 

I o ile wszystko działa OK, tak php-fpm sprawia mi problem, którego nie jestem w stanie rozwiązać. Mianowicie, workery są uruchamiane poprawnie. Jednak ni w ząb, nie da się do nich połączyć.

 

W celu wykluczenia błędu w konfiguracji, uruchomiłem ręcznie interpreter jako responder na FastCGI działający na identycznym porcie i uprawnieniach, co w konfiguracji php-fpm. O dziwo, wszystko działa prawidłowo, więc konfiguracja serwera jest prawidłowa.

 

Oto odpowiedź serwera w przypadku korzystania z php-fpm:

 

HTTP/1.1 404 Not Found
Server: nginx/1.0.5
Date: Thu, 18 Aug 2011 10:11:45 GMT
  Content-Type: text/html
Transfer-Encoding: chunked
Connection: keep-alive
X-Powered-By: PHP/5.3.6

 

Natomiast ten sam skrypt wywołany przy responderze uruchomionym ręcznie działa bez zarzutu (w tym przypadku plik z wyłącznie phpinfo()).

 

Macie jakieś pomysły? Kopię już drugi dzień w Google i konfiguracji; na IRC-ach głównych zainteresowanych nie dowiedziałem się, niestety, niczego... :(

Edytowano przez eRIZ (zobacz historię edycji)

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

 

Zastanawia mnie ten wpisu u Ciebie,

fastcgi_param  SCRIPT_FILENAME /tmp/index.php;

 

w mojej konfiguracji wpis ten wygląda

 

fastcgi_param SCRIPT_FILENAME /www/katalog_ze_stroną/$fastcgi_script_name;

Edytowano przez elroy (zobacz historię edycji)

Udostępnij ten post


Link to postu
Udostępnij na innych stronach
Zastanawia mnie ten wpisu u Ciebie,

 

Podrzuciłem plik testowy, żeby wykluczyć problemy ze ścieżką.

 

Jeśli jest w tmp to nie ma się co dziwić że sypie 404

 

Jakakolwiek ona nie jest - uprawnienia przestawiłem, z katalogu domowego jest to samo. Poza tym:

 

W celu wykluczenia błędu w konfiguracji, uruchomiłem ręcznie interpreter jako responder na FastCGI działający na identycznym porcie i uprawnieniach, co w konfiguracji php-fpm. O dziwo, wszystko działa prawidłowo, więc konfiguracja serwera jest prawidłowa.

 

Więc dlaczego via php-fpm miałoby nie działać?

 

 

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

Więc dlaczego via php-fpm miałoby nie działać?

 

Bo to PHP :P Spróbuj pogmerać z cgi.fix_pathinfo w php.ini (w obie strony), ustaw SCRIPT_NAME (nie SCRIPT_FILENAME, to ma IIRC być pełną ścieżką do skryptu) na puste, $request_filename albo $fastcgi_script_name (testuj i FPM, i tradycyjne FastCGI).

 

To tak na pałę, bo fpma nie miałem pod palcami (tzn. miałem dawno temu i zdążyłem zapomnieć). Jak nie pomoże to strace żeby ustalić co tak naprawdę idzie po drucie do PHP i gdzie ten PHP tego skryptu szuka.

 

W sumie to może właśnie teraz masz taką kombinację subtelnych błędów w fastcgi_params i cgi.fix_pathinfo że standardowe SAPI FastCGI robi co trzeba (specyfikacja jest mętna więc o to wcale nietrudno żeby nap\w+dalać aż zadziała). A w FPM chcieli zrobić światu dobrze i zabili hacki. Mogło tak być, jakbym wprowadzał nowe SAPI to też pozabijałbym wszystkie hacki w starym -- migracja to dobry czas na takie zmiany ;)

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

Już próbowałem wszystkiego - podsłuchałem ktracem, jak sobie nginx z php rozmawia i w obu przypadkach ścieżki w żądaniach są prawidłowe.

 

Gdy wyłączę fix_pathinfo, wywala no input file specified. Gdy włączę - sytuacja jest taka, jak opisałem.

 

Pogrzebałem trochę ktracem i wyniki są następujące. Dla php-fpm

 

SCRIPT_FILENAME/sciezka/index.php
QUERY_STRING
REQUEST_METHODGET
CONTENT_TYPE
CONTENT_LENGTH
SCRIPT_NAME/index.php
REQUEST_URI/index.php
DOCUMENT_URI/index.php
DOCUMENT_ROOT/sciezka
SERVER_PROTOCOLHTTP/1.1
GATEWAY_INTERFACECGI/1.1
SERVER_SOFTWAREnginx/1.0.5

 

 

i dla ręcznie spawnowanego FastCGI:

 

SCRIPT_FILENAME/sciezka/index.php
QUERY_STRING
REQUEST_METHODGET
CONTENT_TYPE
CONTENT_LENGTH
SCRIPT_NAME/index.php
REQUEST_URI/index.php
DOCUMENT_URI/index.php
DOCUMENT_ROOT/sciezka
SERVER_PROTOCOLHTTP/1.1
GATEWAY_INTERFACECGI/1.1
SERVER_SOFTWAREnginx/1.0.5

 

(wyciąłem nagłówki odpowiadające za porty i adresy IP komunikacji przeglądarki z serwerem; ścieżka oczywiście jest prawidłowa)

 

Gdy wyłączę fix_pathinfo, zwraca no input file specified, gdy włączę, to pod php-fpm zwraca błąd przeglądarki.

Edytowano przez eRIZ (zobacz historię edycji)

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

Gdy wyłączę fix_pathinfo, zwraca no input file specified, gdy włączę, to pod php-fpm zwraca błąd przeglądarki.

 

A jak wyłączysz fix_pathinfo to stare SAPI FastCGI przestaje działać? Mam wrażenie że tak i że jak doprowadzisz je do działania z fix_pathinfo=0 to i FPM poleci.

 

Sorry ale nie mam teraz opcji zagrzebać się we wnętrznościach PHP i szukać w kodzie co i jak. Może poszukaj w sapi/cgi/cgi_main.c co dokładnie robi fix_pathinfo i zrób to samo po stronie nginxa (siakieś REDIRECT_STATUS, SCRIPT_PATH_TRANSLATED i tego typu herezje).

Udostępnij ten post


Link to postu
Udostępnij na innych stronach
A jak wyłączysz fix_pathinfo to stare SAPI FastCGI przestaje działać? Mam wrażenie że tak i że jak doprowadzisz je do działania z fix_pathinfo=0 to i FPM poleci.

 

Działa bez najmniejszych problemów, niezależnie od tego ustawienia. A z php-fpm są cyrki...

 

Może poszukaj w sapi/cgi/cgi_main.c co dokładnie robi fix_pathinfo i zrób to samo po stronie nginxa (siakieś REDIRECT_STATUS, SCRIPT_PATH_TRANSLATED i tego typu herezje).

 

W źródłach nie grzebałem, ale kombinowałem z REDIRECT_STATUS i niestety, bez większych sukcesów.

 

Skoro przy zwykłym FCGI działa niezależnie od fix_pathinfo, to chyba nie ma co grzebać w źródłach w tym celu...

Edytowano przez eRIZ (zobacz historię edycji)

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

Skoro przy zwykłym FCGI działa niezależnie od fix_pathinfo, to chyba nie ma co grzebać w źródłach w tym celu...

 

No to ćwiczenie dla czytelnika: czym się różni obsługa protokołu FastCGI w tych dwóch SAPI. Ja osobiście bym jednak w źródłach poszukał, są obrzydliwe ale siłą rzeczy najbardziej wiarygodne.

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

No właśnie kopię w źródłach i póki co, niczego niepokojącego nie widzę, zważywszy na to, że problem jest dość odosobniony...

 

Wszelkie wskazówki mile widziane, bo w C wymiataczem nie jestem i coś mi może umknąć.

 

 

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

Znalazłem coś takiego:

 

if (!ptr) {
				/*
				 * if we stripped out all the '/' and still didn't find
				 * a valid path... we will fail, badly. of course we would
				 * have failed anyway... we output 'no input file' now.
				 */
				if (orig_script_filename) {
					_sapi_cgibin_putenv("ORIG_SCRIPT_FILENAME", orig_script_filename TSRMLS_CC);
				}
				script_path_translated = _sapi_cgibin_putenv("SCRIPT_FILENAME", NULL TSRMLS_CC);
				SG(sapi_headers).http_response_code = 404;
			}

 

Dobrze kopię?

 

 

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

Znalazłem coś takiego:

 

if (!ptr) {
				/*
			     * if we stripped out all the '/' and still didn't find
			     * a valid path... we will fail, badly. of course we would
			     * have failed anyway... we output 'no input file' now.
			     */
				if (orig_script_filename) {
					_sapi_cgibin_putenv("ORIG_SCRIPT_FILENAME", orig_script_filename TSRMLS_CC);
				}
				script_path_translated = _sapi_cgibin_putenv("SCRIPT_FILENAME", NULL TSRMLS_CC);
				SG(sapi_headers).http_response_code = 404;
			}

 

Dobrze kopię?

 

 

 

 

Te okolice ;) A na poziomie "tak ogólnie o co tu biega" to C i PHP są do siebie wystarczająco podobne żeby sobie poczytać bez konieczności wymiatania.

 

Raczej nie znajdziesz wielkiego mrugającego neonu "o, tu robimy czary" ale jeżeli znajdziesz miejsce odpowiedzialne za wyserwowanie Twojego błędu (możliwe że to ten wklejony przez Ciebie kawałek) i przeanalizujesz, jak się tam znalazłeś to będziesz w domu ;)

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

Kolejny dzień roztrzaskiwania mojego mózgu o dziwny problem.

 

Do czego udało mi się dotrzeć. W pliku fpm_main.c jest odwołanie do:

 

/* path_translated exists, we can continue ! */
if (php_fopen_primary_script(&file_handle TSRMLS_CC) == FAILURE) {

 

Owszem, zwraca failure. Ale najciekawszy jest powód błędu:

 

zlog(ZLOG_NOTICE, "WTF: %d", errno);

 

zlog, to wbudowana funkcja do rzucania błędami do konsoli, jeśli php-fpm ma wyłączone w konfiguracji daemonize. Po wykonaniu żądania dla wyłączonego cgi.fix_pathinfo ta zmienna ma wartość errno = 2. Wyczytałem w Sieci, że taki kod jest zwracany, gdy poszukiwany plik nie istnieje (nie żaden brak uprawnień, czy coś; po prostu nie istnieje).

 

Idąc dalej php_fopen_primary_script siedzi w fopen_wrappers.c i zwraca status FAILURE w kilku przypadkach. W moim przypadku sypie z tego powodu:

 

if (filename) {
	resolved_path = zend_resolve_path(filename, strlen(filename) TSRMLS_CC);
}

 

resolved_path jest po prostu... puste. Co powoduje wysypanie następującego warunku:

 

f (!resolved_path) {
	if (SG(request_info).path_translated != filename) {
		STR_FREE(filename);
	}
	/* we have to free SG(request_info).path_translated here because
	 * php_destroy_request_info assumes that it will get
	 * freed when the include_names hash is emptied, but
	 * we're not adding it in this case */
	STR_FREE(SG(request_info).path_translated);
	SG(request_info).path_translated = NULL;
fprintf(stderr, "plecy3\n");
	return FAILURE;
}

 

Dobierając się dalej: zend_resolve_path to tak naprawdę łańcuszek do php_resolve_path. Namierzyłem dziwny punkt:

 

if ((*filename == '.' &&
     (IS_SLASH(filename[1]) ||
      ((filename[1] == '.') && IS_SLASH(filename[2])))) ||
    IS_ABSOLUTE_PATH(filename, filename_length) ||
    !path ||
    !*path) {
	if (tsrm_realpath(filename, resolved_path TSRMLS_CC)) {
		return estrdup(resolved_path);
	} else {
		fprintf(stderr, "resolve plecy4: TSRM: %s, resolved_path: %s\n", tsrm_realpath(filename, resolved_path TSRMLS_CC), resolved_path);
		return NULL;
	}
}

 

Thread Safe Resource Manager - nie wiem, po kiego grzyba coś takiego, ale niech będzie; w pliku TSRM/tsrm_virtual_cwd.c siedzi to dziadostwo. Jest stałą debugująca, która pozwala na dumpowanie do stderr każdego etapu wyciągania. Po jej włączeniu i przekompilowaniu interpretera na starcie otrzymuję:

 

cwd =  path = /usr/local/sbin/php-fpm
virtual_file_ex() = /root/php5.3-201108181230/sapi/fpm/php-fpm
cwd =  path = /usr/local/etc/php.ini
virtual_file_ex() = /usr/local/etc/php.ini

 

 

a dla plików puszczonych via FCGI:

 

cwd =  path = /sciezka/index.php

 

Czyli powinno to coś działać. Ale nie działa. Funkcja tsrm_realpath stopuje na:

 

if (virtual_file_ex(&new_state, path, NULL, CWD_REALPATH)) {
	free(new_state.cwd);
	return NULL;
}

 

Tylko nie wiem, dlaczego... Przecież ścieżka jest prawidłowa i dostępna...

 

 

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

Powiedzenie, że ilość kodu powodująca problem jest odwrotnie proporcjonalna do jego powagi jednak jest istotne.

 

Znalazłem przyczynę - po 5 dniach walki i 3 grzebania w źródłach. Problemem był chroot i ścieżka bezwzględna jako SCRIPT_FILENAME miast względem chrootowanego katalogu.

 

Dzięki za poświęcony czas.

 

 

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

Bądź aktywny! Zaloguj się lub utwórz konto

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto

Zarejestruj nowe konto, to proste!

Zarejestruj nowe konto

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się


×