Autor wpisu: Zyx, dodany: 11.09.2010 10:41, tagi: php
Autor wpisu: m1chu, dodany: 10.09.2010 11:57, tagi: php
Po niespełna dwóch latach pora na kontynuację zabawy. Tym razem poziom wyżej i mieszanka: jedno zadanie dotyczące języka kompilowanego, a drugie skryptowego. A przed tym, rozwiązanie poprzedniej zagadki…
CodeTwister (#1) – rozwiązanie
W listopadzie 2008 roku zamieściłem prosty quiz dotyczący kodu XHTML, CSS i JavaScript. Rozwiązanie opierało się na poprawieniu czterech błędów:
- W przypadku użycia negatywnego komentarza warunkowego strona przestaje być prawidłowym dokumentem XHTML. Tym bardziej wewnątrz arkusza stylów. Style przeznaczone dla Internet Explorera powinny więc być umieszczone w ukrytych komentarzach warunkowych lub za pomocą odpowiednich haków.
<![if !IE]> div#container p { color: #ccc; } <![endif]>
- Znacznik
comment
nie jest elementem XHTML.<comment>Nie używasz</comment>
- Nie można w poniższy sposób dodać elementu z zawartością do jakiegokolwiek potomka
body
ponieważ kod JavaScript wykonywany jest przed załadowaniem dokumentu XHTML. W celu rozwiązania problemu można wykorzystać m.in. możliwości frameworków, elementuonload
albo zdarzeńDOMContentLoaded
lubwindow.onload
.<script type="text/javascript"> <!-- if ( navigator.appName == "Microsoft Internet Explorer" && navigator.appVersion.indexOf("MSIE 7") > -1 ) { var p = document.createElement('p'); p.appendChild(document.createTextNode("Wersja silnika IE: " + navigator.appVersion)); document.body.firstChild.appendChild(p); } --> </script>
- Brak wymaganego znacznika title.
Najbliżej rozwiązania był więc gruch4. Gratulacje!
A w nowym pakiecie…
Zadanie 1 w PHP: problem ze zwracanym wynikiem
Wykonujemy poniższy kod PHP:
$zmienna_poczatkowa = 10; $zmienna_wynikowa = ((~$zmienna_poczatkowa)^(1+8)) << 2; var_dump($zmienna_poczatkowa, $zmienna_wynikowa);
Dlaczego poniższy kod w wyniku zwraca wartość ujemną (int(10) int(-16))? Jak powinna wygląda poprawnie skonstruowana składnia? Jaki będzie wtedy wynik?
Zadanie 2 w C/C++: błędny kod
Znajdź błędy w poniższym kodzie C/C++. Czego w nim brakuje?
#include <stdio.h> #include <windows.h> #define SIZE 200 int main() { int *m = malloc(SIZE*sizeof(int)), i; char small = 'x', large = 'y'; for (i = 0; i < SIZE; ++i) { if ( !(i % 2) ) printf("%s: %d\n", small, (*(m + i) = i * i)); else printf("%s: %d\n", large, (*(m + i) = i * i)); } free(m); return 0; }
Życzę wszystkim powodzenia! :]
Autor wpisu: matipl, dodany: 08.09.2010 11:44, tagi: php, internet
Od września w Polsce działa znana niemiecka firma 1&1.
Do tej pory swoje oddziały otworzyła m.in. w USA, Wielkiej Brytanii, Francji czy Hiszpanii. Łącznie zarządza 11 mln domen.
Polscy klienci będą obsługiwani przez data center w Karlsruhe (Niemcy). Na początek mamy dostępny tylko jeden produkt, ale za to jaki – 1&1 Pakiet na Dzień Dobry.
- Domena w pakiecie – 1 .pl
- administracja DNS
- Powierzchnia dyskowa – 10 GB (domyślnie 1 GB)
- Transfer miesięczny – 3000 GB
- Pojemność skrzynki pocztowej – 2 GB
- Skrzynki pocztowe z IMAP i POP3 – 100
- Bazy danych MySQL – 10
- PHP, Perl, Python
- Telefoniczna pomoc techniczna: Od poniedziałku do piątku w godzinach od 8:00 do 20:00
Cena: 0 zł
Okres: 2 lata
Promocja na aktywację darmowego pakietu trwa do 30 listopada 2010 roku. Ich strona dopiero raczkuje, mogą pojawić się jakieś błędy niestety.
Mimo wszystko hosting z 3 TB danych miesięcznie i PHP za darmo, i do tego jeszcze domena .pl. Na pewno warto spróbować, a z czasem na pewno 1&1 poszerzy ofertę w Polsce. Pierwsze testy na 1&1 przeprowadził już m.in. Gachowy.
Autor wpisu: sokzzuka, dodany: 07.09.2010 16:28, tagi: php
W pewnym momencie naszej kariery, gdy popełnimy już troszkę kodu i zaczniemy tworzyć oprogramowanie w skali większej od stronek-wizytówek często zaczynają się pojawiać problemy z utrzymaniem właściwej jakości oprogramowania. Serwisy jakie tworzymy zaczynają mieć coraz bardziej skomplikowane reguły biznesowe. Zaczynamy stosować więc wzorce projektowe i… i czasami nam to wychodzi a czasami nie. Po pewnym czasie gdy nabierze się doświadczenia, można zapytać się samego siebie, czy tak naprawdę poprawiliśmy jakość swojego kodu. Patrząc na stary kod i nowy kod, większość z nas pewnie odpowie, że jakość się znacznie polepszyła, kod jest ładnie sformatowany, nauczyliśmy się pisać klasy, wprowadziliśmy wzorce, w zasadzie wszystko ok. Natomiast wielokrotnie może być to złudne wrażenie. Ciężko jakość kodu ocenić „na oko”. Dlatego też mądrzy ludzie gdzieś w Ameryce (nie łudźmy się, w Polsce by się nie przebili ;P) wymyślili coś takiego jak metryki kodu.
Czym są metryki kodu ?
Metryka jest miarą, dzięki której możemy coś zmierzyć. W tym przypadku metryka kodu będzie pewną miarą kodu, wikipedia podaje kilkanaście rodzajów metryk, jednak w tym artykule chciałbym przedstawić tylko pokrótce te, które można wygenerować za pomocą narzędzia Php Depend. Php Depend jest skryptem php działającym z linii komend, który umożliwia wyliczenie metryk kodu dla plików php.
Jak go używać ?
Po pierwsze, należy go ściągnąć z repozytorium git-a. Na szczęście nie trzeba klonować repozytorium albowiem na git-hub’ie można ściągnąć od razu spakowane paczki. Gdy już rozpakujemy naszego zip’a należy przejść w command line’ie do katalogu z php dependem oraz wydać komendę php pdepend.php --jdepend-chart=ścieżka/chart.svg --summary-xml=ścieżka/metrics.log --overview-pyramid=ścieżka/pyramid.svg ŚĆIEŻKA_DO_ANALIZOWANEGO_KATALOGU
. Ta komenda po analizie kodu obecnego w danym katalogu wygeneruje nam trzy pliki:
- chart.svg – wykres niestabilności do abstrakcji
- metrics.log – xml z metrykami każdego pliku
- pyramid.svg – wykres słupkowy z metrykami całego katalogu(paczki)
- Instability – miara tego jak bardzo paczka (zbiór klas) jest odporna na zmiany w innych paczkach tj. jak bardzo zależy od innych paczek. Czym większa niestabilność paczki tym więcej trzeba będzie zmieniać w jej klasach gdy klasy z innych paczek zostaną zmodyfikowane.
- Abstraction – abstrakcja – ilość klas abstrakcyjnych / interfejsów do sumarycznej ilości klas w paczce
- LOC – lines of code – ilość lini kodu jakie zawiera paczka
- CYCLO – cyclomatic complexity – miara skomplikowania kodu, jest proporcjonalna do ilości struktur kontrolnych (if, switch, goto, pętle)
- NOC – number of children – polega na zliczaniu liczby klas potomnych danej klasy
- NOP – number of packages – liczba paczek, za paczkę liczy się katalog w tym przypadku
- NOM- number of methods – liczba metod
- ANDC – Average Number of Derived Classes: Średnia liczba klas, które bezpośrednio dziedziczą z danej klasy, nie uwzględnia klas zewnętrznych
- AHH – Average Hierarchy Height: wyliczona średnia drzewa dziedziczenia, nie uwzględnia klas zewnętrznych.
-
Pliki można obejrzeć pod firefox’em. Natomiast ważniejsze jest to co przedstawiają.
Wymienione powyżej metryki kodu są metrykami, które można odczytać z obu wykresów i w głównej mierze mają charakter statystyczny / ilościowy, głównie zliczają ilość klas, linii kodu etc. Natomiast najważniejszą rzeczą w mierzeniu oprogramowania jest aspekt jakościowy, postaram się go bardziej zagospodarować w kolejnym artykule
Autor wpisu: Śpiechu, dodany: 06.09.2010 21:25, tagi: php
Tytuł brzmi nieco niedorzecznie, co? Język stworzony do tworzenia stron WWW posłuży nam do manipulowania plikami multimedialnymi. Za sprawą Vladimira Goreja i jego skryptu FFmpeg PHP opublikowanego na phpclasses.org jest to możliwe.
Skrypt korzysta z bibliotek ffmpeg (wersji na Windowsa chyba nie ma). Mając duży plik na serwerze możemy wyciągać z niego takie rzeczy jak czas trwania, liczba klatek na sek., szerokość i wysokość, bitrate i inne. Najistotniejszą dla nas funkcją jest możliwość wyciągnięcia danej klatki z pliku i zapisanie go na dysku w postaci pliku jpg.
Zanim zaczniecie cokolwiek z tym robić proszę o poprawienie linii 635 pliku FFmpegMovie.php na
exec('ffmpeg -ss '.$frameTime.' -i '.escapeshellarg($this->movieFile).' -vframes 1 -sameq '.$frameFilePath.' 2>&1');
Zgłaszałem to autorowi kilka dni temu, ale na razie bez odzewu. Okazuje się, że wywołując ffmpeg z konsoli, kolejność podawanych atrybutów ma kolosalne znaczenie w szybkości działania. Jeżeli wyciągamy klatkę z początku filmu to pal sześć, gorzej jak gdzieś z końca!
Sama obsługa skryptu jest bajecznie prosta: tworzymy sobie obiekt FFmpegMovie
i używamy funkcji getFrame()
.
require_once('./libs/FFmpegMovie.php'); require_once('./libs/FFmpegFrame.php'); $ffMovie = new FFmpegMovie('./jakis-plik.avi'); $frameNum = floor($ffMovie->getFrameCount() / 2); // wyciągamy ze środka pliku $ffMovie->getFrame($frameNum);
Mamy tutaj niestety kilka mankamentów:
- klatka nie jest takiej samej jakości jak oryginał,
- klatkę trzeba najpierw wyrzucić jako GD resource za pomocą metody
toGDImage()
i potem zapisać funkcjąimagejpeg()
, - nie wiemy czy pobrana klatka jest cała czarna (czyli bezużyteczna),
- nie mamy ładnego wyświetlania z którego momentu filmu pobrano klatkę
Na pierwszy zarzut nic nie pomożemy — jest to wbudowane ograniczenie w ffmpeg, ale za to na resztę można coś zaradzić — stworzyć klasę SpiechuSmartFrame
dziedziczącą po FFmpegFrame
.
class SpiechuSmartFrame extends FFmpegFrame { protected $isBlack = null; /** * @return bool */ public function isBlack() { if ($this->isBlack == null) { $frame = new BlackFrameFinder($this->toGDImage()); $this->isBlack = $frame->isBlack(); } return $this->isBlack; } /** * @return string Returns frame time in hh:mm:ss format */ public function getFrameTimeString() { return gmdate("H:i:s",$this->getPts()); } /** * @param string $filename * @param int $quality quality of jpg file (100 best, 0 worst) * @return bool true if saving to file was success */ public function saveToJpg($filename, $quality = 85) { return imagejpeg($this->toGDImage(), $filename, $quality); } }
Funkcja isBlack()
może być dla Was zapewne niezrozumiała. Kod klasy BlackFrameFinder
jest na tyle długi, że wkleiłem go do Pastebin. Klasa wykrywa czy obrazek jest czarny w ten sposób:
- skaluje obrazek źródłowy na kwadrat 24x24 px,
- zlicza kolory wszystkich pikseli i przelicza je na kolor w skali szarości,
- zlicza kolory od czarnego do „prawie czarnego” (ja przyjąłem indeksy kolorów od 0–20),
- porównuje czy przekroczono limit czarnych punktów (przyjąłem więcej niż 70% całości obrazka)
Klasa oczywiście nie jest „przyspawana” do wykrywania wyłącznie czarnych klatek z filmów. Działa na dowolnych obrazach. Jak zwykle możecie robić sobie z nią co chcecie pod warunkiem zostawienia komentarza pochwalnego i kliknięcia na „Lubię to”
Nie zapomnijcie zmodyfikować oryginalnego pliku FFmpegMovie.php w linii 651 na
Autor wpisu: sokzzuka, dodany: 06.09.2010 15:55, tagi: php
Jednym ze wzorców, który pojawia się często w kontekście Domain Driven Design jest wzorzec specyfikacji. Jest to wzorzec, przekształcający reguły biznesowe na logikę Boole’a. Dzięki wzorcowi specyfikacji, możemy w elastyczny sposób sprawdzić, czy dany obiekt spełnia nasze regułu biznesowe. Tłumacząc go na język interfejsów dostajemy coś takiego:
interface ISpecification { /** * @return boolean */ public function isSatisfiedBy($candidate); /** * @return ISpecification */ public function andSatisfiedBy(ISpecification $otherSpec); /** * @return ISpecification */ public function orSatisfiedBy(ISpecifiaction $otherSpec); public function not(); }
Metoda isSatisfiedBy
sprawdza czy dany obiekt spełnia warunki reguły. Metoda not()
neguje nam warunek, natomiast metody „andSatisfiedBy” i „orSatisfiedBy” umożliwiają nam łączenie reguł w łańcuchy. Łańcuchy te będą połączone odpowiednimi operatorami logicznymi – „and” albo „or”.
Poniżej zaprezentuje implementacje na przykładzie kawałka wyimaginowanej aplikacji do obsługi poborowych zrealizowanej w metodyce DDD. Nasz model będzie składał się z trzech klas:
/** * @entity */ class CPoborowy { protected $_pesel; protected $_imie; protected $_nazwisko; protected $_waga; protected $_wzrost; protected $_ksiazeczkaWojskowa; public function __construct($pesel, $imie, $nazwisko, CWaga $waga, CWzrost $wzrost){ $this->_pesel = $pesel; $this->_imie = $imie; $this->_nazwisko = $nazwisko; $this->_waga = $waga; $this->_wzrost = $wzrost; } public function getWzrost(){ return $this->_wzrost; } public function getWaga(){ return $this->_waga; } public function zrobJaskolke(){ echo 'robie jaskolke'; } public function odbierzKsiazeczkeWojskowa(CKsiazeczkaWojskowa $kw){ if(empty($this->_ksiazeczkaWojskowa)){ $this->_ksiazeczkaWojskowa = $kw; return 'Dziękuje uprzejmie'; } return 'Mam juz ksiazeczke'; } }
Klasa „poborowy” reprezentuje nam osobę poborowego, który określony jest kilkoma parametrami ważnymi dla członków komisji uzupełnień – imię, nazwisko, wzrost i waga. Posiada konstruktor, dwa getter’y oraz metody „odberzKsiazeczkeWojskowa” oraz „zrobJaskolke”, które są niezbędne dla logiki biznesowej rekrutacji do wojska .
Jak pewnie zauważyliście, w konstruktorze przy parametrach „wzrost” i „waga” mamy typehint’y na CWzrost i CWaga.
/** * @value */ class CWzrost { protected $_wartosc; protected $_jednostka; public function __construct($wartosc, $jednostka){ $jednostka = strtolower($jednostka); if($wartosc <= 0){ throw new InvalidArgumentException('Wzrost musi byc wiekszy od 0!'); } if(!in_array($jednostka,array('cm','mm','m'))){ throw new InvalidArgumentException('Dozwolone jednostki to cm, mm i m'); } $this->_wartosc = $wartosc; $this->_jednostka = $jednostka; } public function __toString(){ return $wartosc.' '.$jednostka; } } /** * @value */ class CWaga { protected $_wartosc; protected $_jednostka; public function __construct($wartosc, $jednostka){ $jednostka = strtolower($jednostka); if($wartosc <= 0){ throw new InvalidArgumentException('Waga musi byc wiekszy od 0!'); } if($jednostka != 'kg'){ throw new InvalidArgumentException('Dozwolona jednostka to kilogram'); } $this->_wartosc = $wartosc; $this->_jednostka = $jednostka; } public function __toString(){ return $wartosc.' '.$jednostka; } }
Obie klasy są tzw. ValueObject’s. W odróżnieniu od poborowego, który jest encją i posiada swój unikalny identyfikator w postaci książeczki wojskowej czy pesel-u, wzrost i waga są bytami nieidentyfikowalnymi – można je rozróżnić tylko po wartości, ubranie tych wartości w klasy ma za zadanie:
- wyróżnienie ich jako ważnej części języka domeny i modelu
- walidacje
gdy przyjrzymy się głębiej, widzimy, że w konstruktorach obu klas zawarta jest logika walidacji – zarówno waga jak i wzrost nie mogą być mniejsze od zera, są też sprawdzane jednostki obu wielkości, w końcu nasza komisja poborowa jest w Polsce gdzie mamy jednostki układu SI. Przejdźmy jednak do sedna, czyli wzorca specyfikacji. Załóżmy, że komisja poborowa kwalifikuje do wojska tylko poborowych o wzroście równym 180 cm i wadze 80 kg. Te dwa warunki tworzą naszą specyfikacje, implementacja będzie wyglądać tak:
class CWzrostSpec extends ASpecification { protected $_wzrost; public function __construct($wzrost){ $this->_wzrost = $wzrost; } public function isSatisfiedBy($candidate){ if($candidate->getWzrost() == $this->_wzrost){ if(isset($this->_and)){ return $this->_and->isSatisfiedBy($candidate); } return true; } elseif(isset($this->_or)) { return $this->_or->isSatisfiedBy($candidate); } return false; } } class CWagaSpec extends ASpecification { protected $_waga; public function __construct($waga){ $this->_waga = $waga; } public function isSatisfiedBy($candidate){ if($candidate->getWaga() == $this->_waga){ if(isset($this->_and)){ return $this->_and->isSatisfiedBy($candidate); } return true; } elseif(isset($this->_or)) { return $this->_or->isSatisfiedBy($candidate); } return false; } }
Przykład użycia:
//okreslamy specyfikacje $oSpec = new CWzrostSpec(new CWzrost(180,'cm')); $oSpec->andSatisfiedBy(new CWagaSpec(new CWaga(80,'kg'))); //tworzymy poborowych $oPoborowy1 = new CPoborowy('123456','Franek', 'Gondala', new CWaga(80,'kg'), new CWzrost(180,'cm')); $oPoborowy2 = new CPoborowy('789123', 'Max', 'Perreira', new CWaga(72,'kg'), new CWzrost(176,'cm')); //sprawdzamy czy poborowi spelniaja nasze kryterium var_dump($oSpec->isSatisfiedBy($oPoborowy1)); var_dump($oSpec->isSatisfiedBy($oPoborowy2));
Dzięki zastosowaniu wzorca specyfikacji, gdy komisja poborowa dostanie nowe wytyczne z Ministerstwa Obrony, będzie można w łatwy sposób zmienić lub dołożyć nowe warunki.
Jak widzimy wzorzec specyfikacji przydaje się przy walidacji obiektów, do walidacji formularzy wystarczyło by jeszcze dodanie metody, która dała by jakąś zwrotną informację o tym, w którym miejscu obiekt nie spełnia specyfikacji. Ponadto wzorca specyfikacji używa się jeszcze w kontekście budowania zapytań do bazy danych a dokładniej do repozytorium. Jak wspomniałem we wcześniejszych artykułach z serii o DDD, repozytorium, jest klasą, która pozwala nam wyszukiwać wcześniej utrwalone obiekty wg pewnych kryteriów. Zamiast więc w klasie repozytorium tworzyć metody typu „findByFirstName”, „findByLastName”, „findBy[a-z0-9_]+” można mieć jedną metodę „find”, która jako argument będzie pobierała obiekt specyfikacji i na jego podstawie tworzyła zapytanie do bazy danych.
Jak zwykle czekam na wszelki feedback .