Autor wpisu: singles, dodany: 07.11.2011 18:38, tagi: internet, php
Od prawie dwóch lat chodził mi po głowie pomysł meetupa poświeconego typowo PHP. Gdzie spotkać mogliby się programiści doświadczeni, jak i Ci dopiero zaczynający swoją przygodę z językiem. Spotkania, które zwracałyby uwage na dobrę praktyki, a nie pisanie kodu PHPa na zasadzie „byle tylko działało”. Spotkania, które pokaże, że dowcip „programista PHP” nie zawsze jest prawdziwy.
Poźniej poznałem ludzi nastawionych pozytywnie to tego pomysłu (głównie za sprawą wszelkiego typu konferencji). W międzyczasie wystartowało meet.js (zbieżność nazw wcale nie jest przypadkowa;), które udowadnia, że da się realizować darmowe meetupy z powododzeniem. Tak więc, zachęcony sukcesem meet.js, z przyjemnością prezentuję inicjatywę meet.php.
Informacje
Nie będę podawał szczegółów tutaj, tylko odeślę na stronę meet.php. Tam znajdziecie informacje na temat pierwszego spotkania – datę, miejsce spotkania, listę prelegentów. Jesteśmy także na Twitterze i Facebooku. Feedback jak najbardziej wskazany i porządany:) Zapraszam do odwiedzin!
Prośba
Tutaj prośba do „braci” ze środowiska PHPowego (i nie tylko) o rozpropagowanie informacji o evencie. Jakakolwiek forma będzie dobra – krótki wpis na blogu, retweet, „lajk” czy też „plus jedynka” ;) Z góry dziękuję za okazaną pomoc :)
Podziękowania
Mimo tego, że projekt tej jest wspólnym dziełem moim oraz Daniela Mendalka (@daniula), ogromne podziękowania należą się także członkom Akademickiego Koła Aplikacji Internetowych oraz ekipie Coworking ZOO.
Autor wpisu: batman, dodany: 07.11.2011 08:00, tagi: php
Dwa tygodnie temu uzyskałem dostęp do nowej chmury przeznaczonej dla PHP, stworzonej przez firmę Zend. Zend Developer Cloud, bo o niej mowa, jest już trzecią chmurą dedykowaną PHP i podobnie jak PHPFog znacząco upraszcza proces tworzenia aplikacji, zdejmując z barków programisty kwestie administracyjne. W przeciwieństwie do PHPFog, Zend Developer Cloud jest darmowa.
Jak zacząć?
Proces tworzenia aplikacji na Zend Developer Cloud rozpoczyna się od utworzenia pojemnika (container). Jest to przestrzeń dla naszych aplikacji, coś w rodzaju serwera, na którym będą uruchamiane aplikacje.
Kilka minut po utworzeniu pojemnika, będziemy mogli wejść na wskazany przez nas adres. W efekcie ujrzymy poniższą stronę. Ważne jest aby zapisać hasło do pojemnika, ponieważ hasło to będzie używane w bazie MySQL oraz w większości innych miejsc, wymagających potwierdzenia naszej tożsamości.
I to wszystko co musimy zrobić, aby rozpocząć pracę w chmurze Zenda. Kolejny krok, to instalacja aplikacji.
Tworzymy aplikację
Stworzenie aplikacji jest równie banalne jak stworzenie pojemnika ją przechowującą. W chwili obecnej nie mamy zbyt dużego wyboru, który zamyka się w obrębie następujących rozwiązań:
- pusta aplikacja PHP – standardowa aplikacja oparta o PHP
- pusta aplikacja Zend Framework – szkielet aplikacji ZF
- pusta aplikacja Zend Framework 2 – szkielet aplikacji ZF2
- Drupal 7.8 – znany i lubiany CMS
- Joomla 1.7 – j.w.
- Magento 1.5.1 – system eCommerce zbudowany w oparciu o Zend Framework
- WordPress 3.2.1 – znany i lubiany system blogowy
- phpBB 3.0.9 – znane i lubiane forum
Tworząc nowy projekt warto wiedzieć, że wszystkie aplikacje zostaną utworzone w domenie pojemnika w podkatalogu o nazwie jaką dla aplikacji wybierzemy.
Z racji zainteresowań, do testów wybrałem Zend Frameworka w wersji pierwszej. Po kliknięciu w przycisk Deploy application, zostałem poproszony o podanie nazwy aplikacji i katalogu, w którym będzie się ona znajdować.
Autor wpisu: Kamil Adryjanek, dodany: 07.11.2011 00:14, tagi: symfony2, php
Od jakiegoś czasu starałem się znaleźć odpowiedni moment / trochę wolnego czasu na zapoznanie się z najnowszą wersją frameworka Symfony. Jako, że wiele osób zastanawia się / rozważa migrację swoich dotychczasowych projektów, bądź też rozpoczęcie nowych na Symfony2 postanowiłem przedstawić moje subiektywne obiektywne zdanie na temat możliwości Symfony2.
Ogromną zaletą Symfony2 jest w pełni przepisany silnik frameworka, który w pełni wykorzystuje możliwości PHP 5.3. Przestrzenie nazw nie tylko rozwiązuje problem konfliktów i długich nazw ale także sprawiają, że ładowanie potrzebnych klas jest teraz znacznie prostsze.
Instalacja
Do ściągnięcia dostępna jest gotowa paczka zawierająca wszystkie biblioteki niezbędne do rozpoczęcia pracy. Osobiście polecam instalację framewokra z Gita (najwygodniej pod Linuxem, chociaż jest też ciekawa wersja pod Windowsa dla zainteresowanych). Dzięki temu wszelkie aktualizacje zewnętrznych bibliotek, czy tez bibliotek frameworka sprowadzają się do aktualizacji plików deps i deps.lock, a następnie wywołania z wiersza poleceń komendy:
</p> <p>php bin/vendors update</p> <p>
Bundles
Symfony2 to przede wszystkim ogromne zmiany w architekturze i organizacji kodu aplikacji. Każda aplikacja składa się teraz z pakietów: bundles – coś na wzór modułu z symfony 1.X, z tym że każdy bundle jest teraz dużo bardziej niezależny: posiada odrębną logikę, konfigurację, klasy Entity czy usługi. Dzięki temu nowy mechanizm rozszerzeń Symfony2 jest w całości oparty o bundles – w sieci można znaleźć wiele ciekawie napisanych rozszerzeń: rozbudowany panel administracyjny wzorowany na Django (SonataAdmin) + szereg rozszerzeń, biblioteka do manipulacji/modyfikacji obrazków inspirowana Pythonowym PILem (Imagine), Goutte, biblioteka do budowania scenariuszy, które są następnie wykorzystywane do testowania funkcjonalności (Behat + Mink).
Formularze
Początkowo bardzo toporne – brakuje dobrej dokumentacji. Stworzenie formularza rejestracji, dodanie walidacji (dodanie zależności między polami) stanowi nie lada wyzwanie. Nie podoba mi się przeniesienie walidacji do klasy yml/xml – tak jakbyśmy wracali do symfony 1.0. Na szczęście są annotacje, które można wykorzystać zarówno w klasach Entity, jak i Models. UWAGA na problem z eAcceleratorem – straciłem kilka dobrych godzin przez problem z obcinaniem komentarzy na serwerze produkcyjnym. eAccelerator nie współpracuje poprawnie z nowymi bibliotekami: Symfony2, Doctrine2, Zend Framework, PHP Unit, … . Niestety po kilku godzinach pracy z formularzami miałem odczucie jakby cały mechanizm był teraz znacznie bardziej skomplikowany i trudny do opanowania.
Autor wpisu: Tomasz Kowalczyk, dodany: 06.11.2011 15:07, tagi: css, php
Autor wpisu: Śpiechu, dodany: 06.11.2011 14:10, tagi: mysql, php
Trochę nie pisałem. Mam nadzieję, że dzisiejszy wpis wszystkim wynagrodzi moją nieobecność. Ostatnio stanąłem przed wyzwaniem zrobienia galerii zdjęć, których kolejność dałoby się dowolnie modyfikować za pomocą przeciągania i upuszczania. Dzisiaj opiszę operacje bazodanowe, a na następny raz jQuery. Będę maksymalnie upraszczał aby nie zaciemniać meritum.
1. Przygotowania
Powiedzmy, że mamy 2 tabele relacyjne odpowiedzialne za przechowywanie galerii i obrazów. Np. takie:
CREATE TABLE `galleries` ( `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, `created` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00', `title` VARCHAR(250) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ; CREATE TABLE IF NOT EXISTS `images` ( `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, `gallery_id` INT(10) UNSIGNED NOT NULL, `filename` VARCHAR(50) NOT NULL, `ordr` INT(10) UNSIGNED NOT NULL DEFAULT '1', `created` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `image_to_gallery` (`gallery_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
Od razu widać dwa dziwactwa: dlaczego pole nazywa się ordr a nie order? Z czystego lenistwa. Order jest słowem zarezerwowanym w SQL (ORDER BY coś tam
). Każdorazowo nazwa pola musiałaby być w nawiasach. Dlaczego pole updated ma domyślną wartość 0000–00-00 00:00:00? Ano dlatego, że CURRENT_TIMESTAMP
można użyć tylko raz w tabeli. Wobec tego stworzymy od razu wyzwalacz (trigger), który przed każdym zapytaniem typu UPDATE
poprawi wartość na taką jak trzeba.
DELIMITER $$ CREATE TRIGGER `updated_current_timestamp` BEFORE UPDATE ON `galleries` FOR EACH ROW BEGIN SET NEW.updated = NOW(); END$$
Na koniec trzeba stworzyć relację 1 galeria do wielu zdjęć.
ALTER TABLE `images` ADD CONSTRAINT `image_to_gallery` FOREIGN KEY (`gallery_id`) REFERENCES `galleries` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
Oznacza to, że kasując galerię od razu pozbędziemy się również wszystkich powiązanych z nią zdjęć. Pliki z dysku oczywiście nie znikną. Można napisać funkcję, która przed usunięciem galerii z bazy najpierw wyrzuca wszystkie powiązane z nią pliki, a dopiero potem wykonuje polecenie DELETE
.
2. Decyzje
Teraz nadszedł czas na poważne decyzje. Chodzi o sposób manipulacji wierszami dotyczącymi zdjęć. Można to zrobić za pomocą PHP. Jest to rozwiązanie prostsze. Powoduje jednak spory narzut komunikacji PHP<—>SQL. W przypadku zwalenia wszystkiego na bazę danych, pchamy logikę wyżej i bliżej modyfikowanych danych. Minusem jest cholerna składnia SQLowa i późniejsze problematyczne utrzymanie kodu. Problem oczywiście nie istnieje gdy robimy galeryjkę na 10 obrazków i przestawimy sobie kolejność ostatniego na przedostatni. Ja raczej podchodzę do rzeczy poważnie i wolę od początku zrobić to tak jak powinno być. Poza tym wyzwalacze i procedury składowane to jest to, co bazodanowe tygryski lubią najbardziej
3. Wykonanie
Każdy nowy rekord tabeli images musi mieć nadany odpowiedni identyfikator pozycji ordr o 1 większy od ostatniego w danej galerii. Mamy trzy rozwiązania: czysty PHP, wyzwalacz wywoływany przed INSERT
em lub procedura składowana. Zapytanie w PHP może wyglądać tak:
$q = $pdo->prepare('INSERT INTO images (filename,gallery_id,ordr) (SELECT ?,?,MAX(ordr)+1 FROM images WHERE gallery_id=? LIMIT 1)'); $q->bindValue(1, 'obrazek.jpg', PDO::PARAM_STR); $q->bindParam(2, $galleryId, PDO::PARAM_INT); $q->bindParam(3, $galleryId, PDO::PARAM_INT); $q->execute();
Wspominam o tym rozwiązaniu dlatego, że ma ciekawą konstrukcję INSERT SELECT
. Zapewne większość z was po kilkunastokrotnej próbie wywołania polecenia INSERT INTO VALUES
i gdzieś tam SELECT
dostanie cholery i rozbije zapytanie na 2: pierwsze sprawdza ostatni ordr, a następne doda 1 i umieści INSERT
em pozostałe dane.
Bazodanowe tygryski wybiorą jednak co innego. Procedury składowane!
DELIMITER $$ CREATE PROCEDURE `insert_image`(IN image_filename VARCHAR(50), IN image_gallery_id INT, OUT last_inserted_id INT) MODIFIES SQL DATA COMMENT 'Inserts new image at the end of given gallery.' BEGIN DECLARE max_order INT; # Zamiast SET zmienna= uzywam SELECT INTO just FOR fun SELECT MAX(ordr) INTO max_order FROM images WHERE gallery_id=image_gallery_id LIMIT 1; # Gdy obrazek jest pierwszy w galerii IF max_order IS NULL THEN SET max_order = 1; ELSE SET max_order = max_order + 1; END IF; INSERT INTO images (filename, gallery_id, ordr) VALUES (image_filename, image_gallery_id, max_order); SELECT LAST_INSERT_ID() INTO last_inserted_id; END$$
Próba wywołania $pdo->lastInsertId()
zakończy się niepowodzeniem (a raczej zerem ). Dlatego potrzebujemy parametru wyjściowego. Poniżej pokazuję jak całość wywołać w PDO:
$q = $pdo->prepare('CALL insert_image(?,?,@lastInsertId)'); $q->bindValue(1, 'obrazek.jpg', PDO::PARAM_STR); $q->bindParam(2, $galleryId, PDO::PARAM_INT); $q->execute(); $outputArray = $pdo->query('select @lastInsertId')->fetch(PDO::FETCH_ASSOC); $lastInsertId = $outputArray['@lastInsertId'];
Ktoś może się zapytać po co te numery ze zmienną wyjściową. PDO i sterownik MySQL w PHP ma szpetny błąd dotyczący obsługi parametrów wyjściowych z procedur składowanych. Podobno w nowszych wersjach jest OK. Trik podany wyżej u mnie działa i oszczędza trochę nerwów.
Autor wpisu: Łukasz Socha, dodany: 06.11.2011 10:48, tagi: php
pobierz w .pdf(przeznaczone do wydruku)
PHP jest obecnie bezdyskusyjnie najpopularniejszym językiem programowania używanym w aplikacjach internetowych. Jego główną zaletą jest prostota i łatwość nauki (chociażby brak jawnych typów). Jednak, ma on także znaczne ograniczenia. PHP nie nadaje się do wykonywania bardziej zaawansowanych algorytmów – język nie posiada odpowiednich narzędzi do tworzenia abstrakcyjnych struktur danych. No to jak sam PHP nie ma takich możliwości, to połączmy go z C++…
Jak to zrobić?
Do uruchamiania programów napisanych w innych językach możemy użyć funkcji popen().
Za manualem:
resource popen ( string $command , string $mode )
Funkcja popen() wykonuje polecenie zawarte w $command – może to być np. program w C++ lub polecenie systemowe systemów operacyjnych UNIX. Parametr $mode określa zaś prawa dostępu do procesu. Funkcja zwraca (w przypadku sukcesu) uchwyt do uruchomionego procesu, w przeciwnym wypadku zwróci false.
Przykładowy program
Żeby zobaczyć jak to wygląda w praktyce stwórzmy prosty program do sortowania liczb. Wykorzystamy sortowanie bąbelkowe.
Najpierw stwórzmy kod w C++:
#include <iostream> #include <string> #include <sstream> using namespace std; void boubleSort(int table[], int size) { int i, j, temp; for (i = 0; i<size; i++) { for (j=0; j<size-1; j++) { if (table[j] > table[j+1]) { temp = table[j+1]; table[j+1] = table[j]; table[j] = temp; } } } } int main(int argc, char** argv) { int n=argc-1; int t[n+1]; for(int i=0;i<n;i++) { stringstream konwersja(argv[i+1]); konwersja>>t[i]; } boubleSort(t, n); for(int i=0;i<n;i++) { cout << t[i]<< " "; } return 0; }
W liniach 5-16 zawarty jest algorytm sortujący. W wierszach 21-24 odbieramy i konwertujemy argumenty przekazywane przy uruchamianiu programu do typu int. Właśnie za pomocą tablicy argv będziemy przekazywać dane ze skryptu PHP. Linie 26-28 wyświetlają wynik na standardowym wyjściu (zostanie on przekazany do skryptu PHP).
Teraz stwórzmy skrypt PHP: