Niezalogowany [ logowanie ]
Subskrybuj kanał ATOM Kanał ATOM    Subskrybuj kanał ATOM dla tagu php Kanał ATOM (tag: php)

Autor wpisu: Diabl0, dodany: 03.03.2009 11:52, tagi: zend_framework, php

Po ostatniej aktualizacji ZF do 1.7.6 w jednym z projektów pojawił się nowy “nieplanowany” wyjątek:

Warning: Exception caught by form: Requested scripts may not include parent directory traversal (”../”, “..\” notation)

Cały wyjątek wygląda następująco:

Warning: Exception caught by form: Requested scripts may not include parent directory traversal ("../", "..\" notation) Stack Trace:
#0 C:\HTDOCS\projekt\library\Zend\View\Abstract.php(816): Zend_View_Abstract->_script('../forms/AddApp...')
#1 C:\HTDOCS\projekt\library\Zend\View\Helper\Partial.php(103): Zend_View_Abstract->render('../forms/AddApp...')
#2 [internal function]: Zend_View_Helper_Partial->partial('../forms/AddApp...', Array)
#3 C:\HTDOCS\projekt\library\Zend\View\Abstract.php(329): call_user_func_array(Array, Array)
#4 [internal function]: Zend_View_Abstract->__call('partial', Array)
#5 C:\HTDOCS\projekt\library\Zend\Form\Decorator\ViewScript.php(130): Zend_View->partial('../forms/AddApp...', Array)
#6 C:\HTDOCS\projekt\library\Zend\Form.php(2595): Zend_Form_Decorator_ViewScript->render('')
#7 C:\HTDOCS\projekt\library\Zend\Form.php(2610): Zend_Form->render()
#8 C:\HTDOCS\projekt\application\cytologia\views\scripts\doctor\addapplication.phtml(6): Zend_Form->__toString()
#9 C:\HTDOCS\projekt\library in C:\HTDOCS\projekt\library\Zend\Form.php on line 2615

Po dokładniejszych oględzinach okazało się że problem tkwi w używaniu względnych ścieżek i “wychodzenia” ponad katalog (więcej: ZF-5748) w widokach. Z jednej strony miło że ktoś dba o nasze bezpieczeństwo, ale z drugiej strony po raz kolejny sprawia to problemy przy migracji istniejących projektów (IMHO zmiany wpływające na kompatabilność w obrębie jednej gałęzi są niedopuszczalne).

Na szczęście zostało to szybko zauważone i dodano możliwość wyłączenia tego sprawdzania.

r14063: ZF-5748: Added ability to override LFI protection as needed Documented fix in new “Zend_View Migration” chapter

Przykładowy kod dla Zend_Layout inicjalizowanego w bootstrapie:

$view = Zend_Layout::getMvcInstance ()->getView ();
$view->setLfiProtection ( false );    // override LFI protection

Inne przykłady za manualem:

// Disabling via constructor
$view = new Zend_View(array('lfiProtectionOn' => false));

// Disabling via exlicit method call:
$view = new Zend_View();
$view->setLfiProtection(false);

Related posts

Autor wpisu: SongoQ, dodany: 02.03.2009 10:13, tagi: sql, symfony, php

Lazy load (wzorzec projektowy) – w przypadku Propela oznaczenie atrybutu modelu lazyLoad powoduje, że zostanie on zwrócony w momencie jego jawnego wywołania. Wykorzystuje się to w przypadku jeśli nie potrzebujemy danego atrybutu (z powodu jego rozmiaru) lub chcemy wykorzystać w późniejszym etapie (w widoku). Najczęściej stosuje się to do typów text (longvarchar), blob, clob.

Definicja w schema.yml

schema.yml

documents:
  id:         { type: integer, required: true, primaryKey: true, autoincrement: true }
  created_at: { type: timestamp }
  name:       { type: varchar, size: 100 }
  content:    { type: longvarchar, lazyLoad: true }

Pobieramy obiekt documents, atrybut content ma ustawionym lazyLoad, zostaje on pominięty w zapytaniu SQL. Jeśli wywołamy metodę ->getContent(), zostanie wykonane dodatkowe zapytanie i pole zostanie zwrócone. Lazy load można wykorzystać w celu zoptymalizowania obiektów Propela, jednak trzeba pamiętać że w momencie żądania zwrócenia atrybutu zostanie wykonane dodatkowe zapytanie do bazy danych.

Related Posts

Autor wpisu: Zyx, dodany: 28.02.2009 15:41, tagi: php

Czy zastanawialiście się, dlaczego oskryptowanie stron WWW tworzy się w językach takich, jak PHP, a nie C czy C++? Albo dlaczego nie używa się w miejsce C Pascala? Popularność zdobyta przez te języki wynikała z faktu innowacyjności oraz trafienia w potrzeby ludzi, pozwalając szybciej i łatwiej tworzyć aplikacje. Jednak w tym wpisie pragnę skupić się na systemach szablonów, właśnie w kontekście tych bagatelizowanych przez wielu spostrzeżeń.

Autor wpisu: Tomasz Sh4dow Budzyński, dodany: 15.02.2009 23:01, tagi: php

Autoload w PHP istnieje od wersji 5.0. Bardzo przydatna „magiczna” funkcja, która potrafi zaoszczędzić trochę zasobów serwera. Ładuje pliki z klasą jedynie w czasie gdy jest ona potrzebna. Rozwiązań jest za pewne wiele, niektórzy przeszukują za każdym razem system plików za nazwą klasy, a niektórzy tworzą specjalne konstrukcje katalogów. Są też rozwiązania ze stworzeniem tablicy z nazwami klas i ścieżką do plików. I to rozwiązanie jest moim zdaniem najbardziej efektywne. Jedynym problemem jest tworzenie takiego pliku z tablicami. Oczywiście możemy ręcznie tworzyć tablice, to jest wersja dla najtwardszych. Innym sposobem jest oczywiście stworzenie prostego narzędzie do tworzenia takiej tablicy.

Pierwsza rzecz to musimy wyszukać wszystkie pliki jakie chcemy przeszukać.

<?php
$path = './';
$dir = new RecursiveIteratorIterator(
    new RecursiveDirectoryIterator($path), RecursiveIteratorIterator::SELF_FIRST
);
 
foreach($dir as $file) {
    //przetwarzanie plików
}
?>

To nam pomoże przeszukać wszystkie pliki php w danym katalogu oraz jego podkatalogach. Jeśli ktoś używa na przykład skryptu Smarty, to pojawia się dużo plików php które napewno nie posiadają żadnej klasy lub też katalogi .svn posiadające dużo plików, gdzie nie znajdziemy niczego nam potrzebnego. Przydało by się to odfiltrować. Np przykład tak:

<?php
if( $file->isFile() 
    and end( explode( '.', $file->getFilename() ) ) == 'php' 
    and strpos($file->getFilename(), '%') === false 
    and strpos( $file->getPath().'/'.$file->getFilename(), '.svn') === false ) {
    //dalsze przetwarzanie plików
}
?>

Pre-kompilowane szablony smarty posiadają znaki ‘%’ więc takie pliki możemy odrzucić. Możemy się pokusić o odrzucenie plików z katalogu gdzie zapisywane są pliki smarty, ale w przypadku zmiany nazwy katalogu, trzeba by było modyfikować skrypt. Wszystkie pliki które posiadają w ścieżce fragment ‘.svn’ także będziemy odrzucać, ponieważ na pewno tam nic nie znajdziemy.

Teraz przystąpimy do samego wyszukiwania klas w plikach. Skorzystamy  z wbudowanej funkcji w token_get_all, która częściowo przetworzy nam kod PHP na poziom leksykalny, co znacząco ułatwi nam wyszukiwanie potrzebnych nam rzeczy. Zasadę może pokaże na przykładzie:

<?php
 
# przykładowa klasa
# <?php
# class NazwaKlasy {
#     //tresc klasy
# }

var_dump( token_get_all( "<?php\n class NazwaKlasy {\n //treść klasy\n }") );
?>

Wynikiem będzie wyświetlenie tablicy 2 wymiarowej. W tym konkretnym przykładzie będzie posiadała ona 11 elementów na pierwszym poziomie. Każdy taki element opisuje pojedynczą jednostkę leksykalną. Listę takich jednostek znajdziecie w dokumentacji PHP. Jak znaleźć nazwę klasy. Każdy znaleziony element jest albo string’iem dla znaków takich jak ( ‘{‘, ‘}’, ‘;’, ‘.’, ‘>’, itp.) lub tablicą 3 elementów. Pojedyncze znaki nas nie interesują, więc szukamy tablic. A dokładniej ułożenia kolejnych 3 elementów. Pierwsze to słowo kluczowe ‘class’ (token T_CLASS), następnie odstęp (white space, token T_WHITESPACE) a na końcu ciąg znaków ( token T_STRING ). I właśnie ten ostatni element w połączeniu z nazwą i ścieżką pliku potrzebny. Więc przetworzenie pliku będzie wyglądać mniej więcej tak:

$tokens = token_get_all( file_get_contents( $file->getPath().'/'.$file->getFilename() ) ); //odczytujemy plik i przetwarzamy
$count = count($tokens); //zliczamy ilość elementów, poprostu optymalizacja dla pętli
for($a=0; $a<$count;$a++ ) {
    if( is_numeric( $tokens[$a][0] ) ) { //sprawdzamy czy element jest opisany tablicą
        if( $tokens[$a][0] == T_CLASS and $tokens[$a+1][0] == T_WHITESPACE and $tokens[$a+2][0] == T_STRING ) { //spełnienie warunku dla kolejnych trzech elementów
            if( isset( $klasy[ trim( $tokens[$a+2][1] ) ] ) ) { //sprawdzenie czy nie istnieją duplikaty klas.
                $double[] = array( trim( $tokens[$a+2][1] ), $file->getPath().'/'.$file->getFilename() );
            } else {
                $klasy[ trim( $tokens[$a+2][1] ) ] = $file; //tworzenie tablicy ze ścieżkami do plików oraz nazwami klas
            }
        }
    }
}

Teraz pozostaje nam tylko otrzymaną tablice zapisać do pliku php. Co chyba nikomu nie sprawi problemu:

<?php
file_put_contents('autoload.array.php', "<?php\n");
foreach( $klasy as $class => $file ) {
	//zapisujemy skrócone ścieżki od aktualnego katalogu w górę
	file_put_contents('autoload.array.php', '$autoload[\''.$class.'\'] = \''.str_replace( getcwd(), '.', realpath($file) ).'\';'."\n", FILE_APPEND);
}
?>

W całości będzie to wyglądać mniej więcej tak:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php
set_time_limit(0);
$klasa = array();
$path = './';
$dir = new RecursiveIteratorIterator(
    new RecursiveDirectoryIterator($path), RecursiveIteratorIterator::SELF_FIRST
);
 
//przetwarzanie plików
foreach($dir as $file) {
	if( $file->isFile() and end( explode( '.', $file->getFilename() ) ) == 'php' and strpos($file->getFilename(), '%') === false and strpos( $file->getPath().'/'.$file->getFilename(), '.svn') === false) {
        $tokens = token_get_all( file_get_contents( $file->getPath().'/'.$file->getFilename() ) );
        $count = count($tokens);
        for($a=0; $a<$count;$a++ ) {
            if( is_numeric( $tokens[$a][0] ) ) {
                if( $tokens[$a][0] == T_CLASS and $tokens[$a+1][0] == T_WHITESPACE and $tokens[$a+2][0] == T_STRING ) {
                    if( isset( $klasy[ trim( $tokens[$a+2][1] ) ] ) ) {
                        $double[] = array( trim( $tokens[$a+2][1] ), $file->getPath().'/'.$file->getFilename() );
                    } else {
                        $klasy[ trim( $tokens[$a+2][1] ) ] = $file;
                    }
                }
            }
        }
	}
}
 
//budowanie pliku z tablicą
file_put_contents('autoload.array.php', "<?php\n");
foreach( $klasy as $class => $file ) {
	file_put_contents('autoload.array.php', '$autoload[\''.$class.'\'] = \''.str_replace( getcwd(), '.', realpath($file)).'\';'."\n", FILE_APPEND);
}
?>

Na początku przydaje się dodać set_time_limit() na zero ponieważ przy dużych plikach oraz przy dużej ich ilości cała operacja może chwilkę potrwać. Należy pamiętać, że po dodaniu nowej klasy, przydałoby się uruchomić skrypt ponownie, aby dodał nową klase do tablicy. Teraz pozostaje nam stworzyć jedynie funkcje __autoload, która będzie korzystać z naszej tablicy.

1
2
3
4
5
6
7
8
9
10
11
$autoload = array();
function __autoload($class_name) {
	static $autoload;
	include_once( './autoload.array.php' );
 
	if( isset( $autoload[ $class_name ] ) ) {
		include_once($autoload[ $class_name ]);
		return true;
	}
	return false;
}

I mamy gotową całą funkcjonalność autoload. Możemy ją poszerzyć o zliczanie ilości plików lub klas, czas wykonywania lub inne mniej lub bardziej przydatne informacje. Wszystko zależy od waszych potrzeb.

Czytaj dalej tutaj (rozwija treść wpisu)
Czytaj dalej na blogu autora...

Autor wpisu: m1chu, dodany: 15.02.2009 13:55, tagi: php

Pobieramy liczbę subskrybentów RSS poprzez FeedBurner

W niezbędniku prawie każdego blogera leży możliwość menadżerowania swoimi kanałami RSS, bądź Atom. Któż z nas nie zna FeedBurner'a?. Zestawu narzędzi ułatwiających nam, czy to udostępnianie użytkownikom możliwości subskrypcji treści naszej strony, czy po prostu możliwość przejrzenia lub zamieszczenia statystyk w naszym serwisie. Pomimo dostarczonego API nie znajdziemy jednak bezpośrednio w panelu FeedBurner'a kodu pozwalającego na umieszczenie samej liczby subskrybentów bloga. I rozwiązanie tego, pozornie błahego problemu postaram się Wam dziś przedstawić...

Stary, dobry FeedBurner.com...

Niespełna dwa lata temu słynny serwis zajmujący się obsługą kanałów RSS został przejęty za sto milionów dolarów przez Google. Pomimo tego, że minęło aż tyle czasu wielu blogerów nadal korzysta z zasobów starego, wysłużonego, pierwotnego FeedBurner'a. I co może wydawać się dziwne, to właśnie oni mają najbardziej ułatwioną sytuację.

Zarówno stara, jak i nowa odsłona serwisu oferują usługę FeedCount dostępną z poziomu menu Publicize. Pozwala ona na dobranie typu wbudowanego tła wyświetlającego ilość subskrybentów (statyczne, bądź animowane) oraz na dobranie jego barwy i koloru tekstu. Wraz z ustawieniem tych parametrów otrzymujemy kod HTML do wstawienia na naszą stronę. I tu rodzi się problem. Prócz kilku stylistycznych zmian wygląd tychże "chickletów" jest zawsze taki sam i najczęściej nijak pasuje do designu naszego bloga. Co zrobić jeżeli np. chcemy wraz z tekstem przycisku odnoszącego użytkowników do wygenerowanego kanału wstawić także ilość osób śledzących naszą stronę?

Rozwiązanie zaprezentuje na podstawie użytkowania platformy Wordpress (oczywiście ilość subskrybentów - opierając się na dalszym tekście - można zamieścić w każdym innym systemie zarządzania treścią, bądź nawet na własnej, prywatnej stronie). W takim wypadku wystarczy zainteresować się wtyczkami FeedSmith 2.3 (polska wersja) (wg. developerów Wordpress'a kompatybilną ze wszystkimi wersjami 2.x) i Feed Count 1.2 (polska wersja). Pierwsza z nich niezbędna jest do obsługi kanału RSS przez serwis FeedBurner.

Jej instalacja oraz rejestracja w serwisie jest niezbędna do działania drugiej z nich. Jak wykonuje się instalacje wtyczek? Wystarczy wyodrębnić z archiwum odpowiednie pliki (w naszym pierwszym przypadku będzie to FeedBurner_FeedSmith_Plugin.php, w drugim feedcount.php) i umieścić je w katalogu wp-content/plugins/ systemu Wordpress. Następnie wtyczki należy zaktywować w panelu administratora (Wtyczki / Nazwa wtyczki / Włącz).

Obydwa pluginy należy dodatkowo skonfigurować w zakładce Ustawienia. Pierwszy z nich swoje opcje ukrywa w podmenu FeedBurner. Zobaczycie tam dwa pola do uzupełnienia, jedno wymagane, drugie opcjonalne. Pierwsze z nich to pełny odnośnik do feedu strony w serwisie FeedBurner (i dla starej odsłony, i dla nowej na serwerach Google), a drugi to link do kanału RSS komentarzy.

Konfiguracja wtyczki FeedSmith w paneluKonfiguracja wtyczki FeedSmith w panelu.

Co do drugiego rozszerzenia to działa ono dla wersji 2.x Wordpress'a, z tymże przy najnowszej 2.7x może sprawiać problemy natury zwracania wyniku w postaci N/A zamiast poprawnej wartości.

Konfiguracja wtyczki Feed Count w paneluKonfiguracja wtyczki Feed Count w panelu.

Czytaj dalej tutaj (rozwija treść wpisu)
Czytaj dalej na blogu autora...

Autor wpisu: Athlan, dodany: 06.02.2009 10:42, tagi: internet, php

Projektowałem wiele serwisów, które miały zintegrowane z forum komponenty takie jak:

  • rejestracja,
  • przypomnienie hasła,
  • zmiana hasła, nicku lub adresu email,
  • usunięcie konta.

Wówczas nie było żadnego problemu - wystarczyło wszystkie te akcje z forum przekierować na URL’e obsługiwane przez CMS, który zajmował się zmianami  tabelach forum. Dlaczego przekierować? Jeżeli ktoś rejestruje się w serwisie, jest zarejestrowany na forum, natomiast, gdy rejestruje się na forum, nie jest rejestrowany w serwisie. To CMS integrujemy z forum, a nie forum z CMS’em (chyba, że zamierzamy inaczej, wtedy na odwrót).

Ostatnio klient zażyczył sobie, żeby zintegrowane było również logowanie. Nie najlepiej widzi mi się implementacja systemu autoryzacji z forum w CMS’ie, więc poszedłem “na łatwiznę”, bowiem miałem do czynienia z phpBB. Do osiągnięcia celu postanowiłem wykonać dwa kroki:

  1. wysłać żądanie POST do forum na adres logowania z wypełnionymi polami POST z formularza logowania w CMS’ie,
  2. przechwycić wysłane przez forum ciasteczka i przekazać je użytkownikowi.

Do połączenia się z forum via http użyłem HttpRequest. Wyszło z tego parę linijek kodu.

Autor wpisu: SongoQ, dodany: 04.02.2009 07:46, tagi: php, apache, sql

Przeprowadziłem kilka testów szybkości odczytu z pliku i tabel typu: MEMORY, MyISAM.

Jak był przeprowadzany test:

Test przeprowadzałem na Ubuntu Dapper (apache2, php5.1.x, MySQL 5.0.22) na laptopie, więc wiele rzeczy mogło wpłynąć na na nieprawidłowość testów.

Test podzieliłem na kilka etapów:

  • z włączonym cache zapytań
  • z wyłączonym cache zapytań
  • z pomiarem połączenia z bazą danych

Odnośnie ilości wywołań testu, to był wykonywany 1000 razy, liczone były pojedyńcze czasy testu, a następnie sumowane i liczona z tego średnia testu. Jako danych testowych użyłem wygenerowanego ciągu znaków o długości około 65 KB.

Wyniki:

Odczyt z pliku:

Do odczytu z pliku użyłem funkcji: file_get_contents() Średni czas odczytu jaki uzyskałem to: 0.000357507705688 (szczegółowe informacje)

Odczyt z bazy danych:

Do odczytu z bazy użyłem funkcji mysql_* (połączenie, wybór bazy, wykonanie zapytanie i zwrócenie rekordu). Tabela zawierała 1 rekord z id i polem w którym był zapisany taki sam ciąg znaków jak w przypadku pliku. Dlaczego nie więcej? Chciałem wyeliminować czas jaki będzie potrzebny na przeliczenie jaki rekord ma zostać zwrócony.

Wyłączony zapis cache w MySQL i czas połączenia z bazą pominięty:

Tabela MyISAM - średni czas to: 0.00516110825539 (szczegółowe informacje) Tabela MEMORY - średni czas to: 0.00368802952766 (szczegółowe informacje)

Widać, że odczyt z pliku ma przewagę nad odczytem z bazy danych, a czasy odczytu z tabel typu MyISAM i MEMORY są bardzo do siebie zbliżone.

Włączony zapis cache w MySQL i czas połączenia z bazą pominięty:

Tabela MyISAM - średni czas to: 0.00179107260704 (szczegółowe informacje)

Czytaj dalej tutaj (rozwija treść wpisu)
Czytaj dalej na blogu autora...

Wszystkie wpisy należą do ich twórców. PHP.pl nie ponosi odpowiedzialności za treść wpisów.