├── .gitignore ├── CNAME ├── LICENSE ├── README.md ├── _config.yml ├── _includes └── welcome.md ├── _layouts ├── default.html └── page.html ├── _posts ├── 01-01-01-Getting-Started.md ├── 01-02-01-Use-the-Current-Stable-Version.md ├── 01-03-01-Built-in-Web-Server.md ├── 01-04-01-Mac-Setup.md ├── 01-05-01-Windows-Setup.md ├── 02-01-01-Code-Style-Guide.md ├── 03-01-01-Language-Highlights.md ├── 03-02-01-Programming-Paradigms.md ├── 03-03-01-Namespaces.md ├── 03-04-01-Standard-PHP-Library.md ├── 03-05-01-Command-Line-Interface.md ├── 03-06-01-XDebug.md ├── 04-01-01-Dependency-Management.md ├── 04-02-01-Composer-and-Packagist.md ├── 04-03-01-PEAR.md ├── 05-01-01-Coding-Practices.md ├── 05-02-01-Exceptions.md ├── 05-03-01-Date-and-Time.md ├── 05-03-01-Design-Patterns.md ├── 06-01-01-Databases.md ├── 07-01-01-Security.md ├── 07-02-01-Web-Application-Security.md ├── 07-03-01-Password-Hashing-with-Bcrypt.md ├── 07-04-01-Data-Filtering.md ├── 07-05-01-Configuration-Files.md ├── 07-06-01-Register-Globals.md ├── 07-07-01-Error-Reporting.md ├── 08-01-01-Testing.md ├── 08-02-01-Test-Driven-Development.md ├── 08-03-01-Behavior-Driven-Development.md ├── 08-04-01-Complementary-Testing-Tools.md ├── 09-01-01-Servers-and-Deployment.md ├── 09-02-01-Platform-as-a-Service.md ├── 09-03-01-Virtual-or-Dedicated-Servers.md ├── 09-04-01-Shared-Servers.md ├── 10-01-01-Caching.md ├── 10-02-01-Bytecode-Cache.md ├── 10-03-01-Object-Caching.md ├── 11-01-01-Resources.md ├── 11-02-01-Frameworks.md └── 12-01-01-Community.md ├── banners.md ├── images ├── banners │ ├── btn1-120x90.png │ ├── btn2-120x60.png │ ├── leaderboard-728x90.png │ ├── lg-rect-386x280.png │ ├── med-rect-300x250.png │ ├── rect-180x150.png │ ├── sq-btn-125x125.png │ └── vert-rect-240x400.png ├── favicon.png ├── nmc-logo.gif └── og-logo.png ├── index.html ├── pages ├── Design-Patterns.md ├── Functional-Programming.md └── example.md ├── scripts └── setup.js ├── sitemap.xml └── styles ├── all.css ├── all.less ├── base ├── all.less ├── bars-buttons.less ├── buttons.less ├── grid.less ├── idioms.less ├── prefixer.less ├── reset.less ├── spacing.less ├── typography.less └── variables.less ├── site ├── site-content.less ├── site-footer.less ├── site-header.less ├── site-navigation.less └── variables.less └── syntax.css /.gitignore: -------------------------------------------------------------------------------- 1 | /_site/ 2 | *.DS_Store 3 | -------------------------------------------------------------------------------- /CNAME: -------------------------------------------------------------------------------- 1 | pl.phptherightway.com 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Josh Lockhart 2 | 3 | http://creativecommons.org/licenses/by-nc-sa/3.0/ 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PHP: The Right Way 2 | 3 | ## Start 4 | 5 | Witaj w repozytorium GitHub Pages dla polskiego tłumaczenia projektu _PHP: The Right Way_! 6 | 7 | * Ta strona jest projektem Jekyll. 8 | * Kolejne sekcje i podsekcje są plikami \*.md (Markdown) w katalogu `_posts/`. 9 | * Podsekcje posiadają wpis `isChild: true` w nagłówku. 10 | * Nawigacja boczna i struktura strony jest generowana automagicznie. 11 | 12 | ## Podziel się dobrą informacją 13 | 14 | _PHP: The Right Way_ udostępnia banery reklamowe, które śmiało możesz umieścić na swojej stronie internetowej, aby 15 | pomóc nam promować tę inicjatywę wśród programistów PHP. 16 | 17 | [Obejrzyj dostępne banery](http://pl.phptherightway.com/banners.html) 18 | 19 | ## Jak mogę pomóc? 20 | 21 | 1. Zrób forka i wprowadź swoje zmiany. 22 | 2. Zainstaluj [Ruby](https://rvm.io/rvm/install/) oraz [Jekyll](https://github.com/mojombo/jekyll/), aby podejrzeć 23 | swoją pracę lokalnie. 24 | 3. Wyślij "pull request", abyśmy mogli rozważyć wprowadzenie Twoich zmian do głównego repozytorium. 25 | 26 | ### Przyjęty styl 27 | 28 | 1. W głównym repozytorium (język angielski) używaj American English. 29 | 2. W polskim repozytorium stosuj poprawną polszczyznę, stosuj właściwą interpunkcję. 30 | 3. Robiąc wcięcia, używaj czterech spacji. Nigdy nie stosuj tabulatorów. 31 | 4. Przykłady kodu powinny przestrzegać PSR-1 lub wyższego. 32 | 33 | ## Gdzie? 34 | 35 | 36 | 37 | * [English](http://www.phptherightway.com) 38 | * [Deutsch](http://rwetzlmayr.github.io/php-the-right-way) 39 | * [Español](http://phpdevenezuela.github.io/php-the-right-way) 40 | * [Français](http://eilgin.github.io/php-the-right-way/) 41 | * [Indonesia](http://id.phptherightway.com) 42 | * [Italiano](http://it.phptherightway.com) 43 | * [Polski](http://pl.phptherightway.com) 44 | * [Português do Brasil](http://br.phptherightway.com) 45 | * [Română](https://bgui.github.io/php-the-right-way/) 46 | * [Slovenščina](http://sl.phptherightway.com) 47 | * [Srpski](http://phpsrbija.github.io/php-the-right-way/) 48 | * [Türkçe](http://hkulekci.github.io/php-the-right-way/) 49 | * [български](http://bg.phptherightway.com) 50 | * [Русский язык](http://getjump.github.io/ru-php-the-right-way) 51 | * [Українська](http://iflista.github.com/php-the-right-way) 52 | * [العربية](https://adaroobi.github.io/php-the-right-way/) 53 | * [فارسى](http://novid.github.io/php-the-right-way/) 54 | * [ภาษาไทย](https://apzentral.github.io/php-the-right-way/) 55 | * [한국어판](http://modernpug.github.io/php-the-right-way) 56 | * [日本語](http://ja.phptherightway.com) 57 | * [简体中文](http://laravel-china.github.io/php-the-right-way/) 58 | * [繁體中文](http://laravel-taiwan.github.io/php-the-right-way) 59 | 60 | ### Tłumaczenia 61 | 62 | Jeżeli jesteś zainteresowany wykonaniem tłumaczenia tego projektu na inny język, sforkuj oryginalne repozytorium i 63 | opublikuj swoje tłumaczenie przy pomocy GitHub Pages. Twoja praca zostanie podlinkowana w głównym dokumencie. 64 | 65 | Masz możliwość uruchomienia swojego tłumaczenia w adresie GitHub, np. `[username].github.com/php-the-right-way` 66 | lub w naszej subdomenie, np. `ru.phptherightway.com`. Jeżeli chcesz skorzystać z subdomeny, wpisz jej nazwę w pliku 67 | `CNAME`, który znajduje się w głównym katalogu projektu. W przeciwnym wypadku usuń ten plik całkowicie, gdyż w 68 | przeciwnym razie Twoja strona nie opublikuje się. 69 | 70 | Po zakończeniu swojej pracy dodaj zgłoszenie w Issue Trackerze oryginalnego repozytorium, abyśmy mogli podlinkować 71 | Twoją pracę. 72 | 73 | ## Dlaczego? 74 | 75 | W Sieci brakuje spójnej instrukcji jak sprawnie rozpocząć programowanie w PHP. Projekt ten ma na celu zmianę tego stanu 76 | rzeczy. 77 | 78 | ## Kto? 79 | 80 | Nazywam się [Josh Lockhart](http://twitter.com/codeguy). Jestem autorem projektu [Slim Framework](http://www.slimframework.com/) i pracuję w firmie [New Media Campaigns](http://www.newmediacampaigns.com/).. 81 | 82 | ### Współpracownicy 83 | 84 | * [Kris Jordan](http://krisjordan.com/) 85 | * [Phil Sturgeon](http://philsturgeon.co.uk/) 86 | 87 | ## Licencja 88 | 89 | Dokument jest udostępniony na licencji Creative Commons [Uznanie autorstwa-Użycie niekomercyjne-Na tych samych warunkach 3.0](http://creativecommons.org/licenses/by-nc-sa/3.0/) 90 | 91 | ## Tłumaczenie na język polski 92 | 93 | Tłumaczenie na język polski wykonał Bartosz Maciaszek. 94 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | baseurl: / 2 | url: http://localhost:4000 3 | 4 | highlighter: pygments 5 | markdown: kramdown 6 | permalink: date 7 | maruku: 8 | use_tex: false 9 | use_divs: false 10 | png_engine: blahtex 11 | png_dir: images/latex 12 | png_url: /images/latex 13 | 14 | gems: 15 | - jekyll-sitemap 16 | 17 | defaults: 18 | - 19 | scope: 20 | path: "" 21 | values: 22 | sitemap: false 23 | 24 | exclude: ['CNAME', 'CONTRIBUTING.md', 'LICENSE', 'README.md', 'pages/example.md'] 25 | -------------------------------------------------------------------------------- /_includes/welcome.md: -------------------------------------------------------------------------------- 1 | # Witaj! 2 | 3 | W Sieci można znaleźć wiele publikacji na temat PHP. Niestety, wiele z nich jest nieaktualnych, niekompletnych lub nie 4 | odnosi się do aktualnych dostępnych wersji. Wprowadza to wszechobecny zamęt i prowadzi nowych fanów tego języka na 5 | przysłowiowe manowce. Tak dalej być nie może. _PHP: The Right Way_ jest przystępnym zbiorem najlepszych praktyk i 6 | standardów kodowania, a także linków do sprawdzonych i solidnych tutoriali pałętających się w czeluściach Internetu. 7 | 8 | ## Tłumaczenia 9 | 10 | _PHP: The Right Way_ jest (lub niebawem będzie) przetłumaczony na wiele języków: 11 | 12 | * [English](http://www.phptherightway.com) 13 | * [Deutsch](http://rwetzlmayr.github.io/php-the-right-way) 14 | * [Español](http://phpdevenezuela.github.io/php-the-right-way) 15 | * [Français](http://eilgin.github.io/php-the-right-way/) 16 | * [Indonesia](http://id.phptherightway.com) 17 | * [Italiano](http://it.phptherightway.com) 18 | * [Polski](http://pl.phptherightway.com) 19 | * [Português do Brasil](http://br.phptherightway.com) 20 | * [Română](https://bgui.github.io/php-the-right-way/) 21 | * [Slovenščina](http://sl.phptherightway.com) 22 | * [Srpski](http://phpsrbija.github.io/php-the-right-way/) 23 | * [Türkçe](http://hkulekci.github.io/php-the-right-way/) 24 | * [български](http://bg.phptherightway.com) 25 | * [Русский язык](http://getjump.github.io/ru-php-the-right-way) 26 | * [Українська](http://iflista.github.com/php-the-right-way) 27 | * [العربية](https://adaroobi.github.io/php-the-right-way/) 28 | * [فارسى](http://novid.github.io/php-the-right-way/) 29 | * [ภาษาไทย](https://apzentral.github.io/php-the-right-way/) 30 | * [한국어판](http://modernpug.github.io/php-the-right-way) 31 | * [日本語](http://ja.phptherightway.com) 32 | * [简体中文](http://laravel-china.github.io/php-the-right-way/) 33 | * [繁體中文](http://laravel-taiwan.github.io/php-the-right-way) 34 | 35 | ## Uwaga 36 | 37 | Nie istnieje żaden standardowy sposób, który określałby w jaki sposób powinieneś korzystać z PHP. Dokument ten ma 38 | jednakże na celu zebrać w jednym miejscu najlepsze praktyki, najważniejsze możliwości języka oraz inne cenne 39 | informacje i przeznaczony jest zarówno dla początkujących programistów, rozpoczynających swoją zabawę z PHP, jak dla 40 | zaawansowanych wyjadaczy, którzy zagłębiając się w jego lekturze będą mieli możliwość przemyślenia swoich 41 | dotychczasowych przyzwyczajeń bądź poznania najlepszych rozwiązań. 42 | 43 | Dokument ten jest wciąż rozwijany oraz uzupełniany o kolejne materiały i przykłady. Jeżeli chciałbyś pomóc w jego 44 | rozwoju, bądź masz uwagi do bieżącego tłumaczenia, przeczytaj poniższy akapit. 45 | 46 | ## Jak mogę pomóc? 47 | 48 | Jeżeli chciałbyś/chciałabyś mieć wpływ na zawartość tego dokumentu lub po prostu chcesz powiedzieć światu o tej 49 | inicjatywie - zapraszamy! 50 | 51 | [Strona projektu w serwisie GitHub][1] 52 | 53 | ## Podziel się dobrą informacją! 54 | 55 | _PHP: The Right Way_ udostępnia banery reklamowe, które śmiało możesz umieścić na swojej stronie internetowej, aby 56 | pomóc nam promować tę inicjatywę wśród programistów PHP. 57 | 58 | [Obejrzyj dostępne banery][2] 59 | 60 | [1]: https://github.com/bartosz-maciaszek/php-the-right-way/tree/gh-pages 61 | [2]: /banners.html 62 | -------------------------------------------------------------------------------- /_layouts/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {% if page.title %}{{ page.title }} - {% endif %}PHP: The Right Way. Po polsku. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 29 | 30 | 31 | 45 |
46 | 47 | 48 | Fork me on GitHub 49 | 50 | 51 | 58 | {{ content }} 59 | 83 |
84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /_layouts/page.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {% if page.title %}{{ page.title }} - {% endif %}PHP: The Right Way. Po polsku. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 29 | 30 | 31 |
32 | 33 |
The Right Way.
34 | Powrót do strony głównej 35 | 36 | Fork me on GitHub 37 | 38 |
39 |
40 | {{ content }} 41 | 46 |
47 | 48 | 49 | -------------------------------------------------------------------------------- /_posts/01-01-01-Getting-Started.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Pierwsze kroki 3 | --- 4 | 5 | # Pierwsze kroki {#getting_started_title} 6 | 7 | -------------------------------------------------------------------------------- /_posts/01-02-01-Use-the-Current-Stable-Version.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Korzystaj z ostatniej stabilnej wersji 3 | isChild: true 4 | --- 5 | 6 | ## Korzystaj z ostatniej stabilnej wersji {#use_the_current_stable_version_title} 7 | 8 | Jeżeli dopiero rozpoczynasz swoją przygodę z PHP, upewnij się, że korzystasz z ostatniej stabilnej wersji (obecnie 9 | [PHP 7.1][php-release]). PHP jest silnie rozwijane i twórcy tego języka wciąż dodają do niego 10 | [nowe, przydatne funkcje](#language_highlights). Mimo tego, że konwencja nadawania kolejnych numerów wersji języka 11 | może sugerować, że zmiany są niewielkie, w rzeczywistości różnice między kolejnymi wersjami są _znaczące_. Na stronach 12 | [php.net][php-docs] dostępna jest obszerna, przetłumaczona na wiele języków dokumentacja zawierająca opis możliwości 13 | języka PHP, jak również spis wszystkich dostępnych funkcji i sposobów ich wywołania. 14 | 15 | W środowiskach produkcyjnych najbardziej rozpowszechnionymi wersjami PHP są obecnie te z zakresu 5.x. 16 | Ostatnią wersją 5.x jest 5.6. Jest to nadal dobra opcja, ale jeśli jesteś odpowiedzialny za jakiś projekt PHP, 17 | to powinieneś jak najszybciej uaktualnić go do najnowszej stabilnej wersji, bo PHP 5.6 18 | [nie będzie otrzymywało poprawek bezpieczeństwa po roku 2018][php-support]. Aktualizacja nie jest skomplikowana, 19 | ale należy uwzględnić kilka zmian, które [nie są kompatybilne wstecznie][php-backwards-compatibility]. 20 | Informacje o dostępności funkcji i funkcjonalności w poszczególnych wersjach PHP dostępne są w [podręczniku PHP][php-docs]. 21 | 22 | [php-release]: http://www.php.net/downloads.php 23 | [php-docs]: http://www.php.net/manual/pl/ 24 | [php-support]: http://php.net/supported-versions.php 25 | [php-backwards-compatibility]: http://php.net/manual/en/migration70.incompatible.php 26 | -------------------------------------------------------------------------------- /_posts/01-03-01-Built-in-Web-Server.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Wbudowany serwer WWW 3 | isChild: true 4 | --- 5 | 6 | ## Wbudowany serwer WWW {#builtin_web_server_title} 7 | 8 | PHP 5.4 (oraz nowsze) posiadają własny, wbudowany w dystrybucję serwer WWW, więc jeżeli korzystasz z wersji 9 | PHP 5.4 lub nowszej, możesz łatwo rozpocząć naukę programownaia bez instalacji standardowego serwera 10 | HTTP, takiego jak Apache. Aby uruchomić serwer, wykonaj następujące polecenie w głównym katalogu 11 | swojego projektu: 12 | 13 | > php -S localhost:8000 14 | 15 | * [Dowiedz się więcej na temat wbudowanego serwera WWW] [cli-server] 16 | 17 | [cli-server]: http://www.php.net/manual/pl/features.commandline.webserver.php 18 | -------------------------------------------------------------------------------- /_posts/01-04-01-Mac-Setup.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Instalacja na Maku 3 | isChild: true 4 | --- 5 | 6 | ## Instalacja na Maku {#mac_setup_title} 7 | 8 | W systemie macOS PHP jest zainstalowane domyślnie, lecz nigdy nie jest to najświeższa wersja. 9 | +Wersja "Mavericks" posiada PHP 5.4.17, "Yosemite" - 5.5.9, "El Capitan" - 5.5.29 a "Sierra" 5.6.24. 10 | 11 | Jest możliwość aktualizacji preinstalowanej wersji PHP do najnowszej - można to zrobić poprzez 12 | [odpowiednie pakiety][mac-package-managers]. Zalecamy instalację [php-osx by Liip][php-osx-downloads]. 13 | 14 | Możesz także [skompilować PHP samodzielnie][mac-compile], ale wcześniej upewnij się, że masz zainstalowany Xcode lub 15 | ["Command Line Tools for Xcode"][apple-developer], które możesz ściągnąć ze strony Mac Developer Center firmy Apple. 16 | 17 | Istnieje również możliwość instalacji pakietu "all-in-one", który zawiera PHP, serwer Apache oraz bazę MySQL wraz z 18 | graficznym interfejsem do zarządzania całym pakietem. Jeżeli interesuje Cię ta opcja, zainteresuj się projektem 19 | [MAMP][mamp-downloads]. 20 | 21 | [mac-package-managers]: http://www.php.net/manual/pl/install.macosx.packages.php 22 | [mac-compile]: http://www.php.net/manual/pl/install.macosx.compile.php 23 | [xcode-gcc-substitution]: https://github.com/kennethreitz/osx-gcc-installer 24 | [apple-developer]: https://developer.apple.com/downloads 25 | [mamp-downloads]: http://www.mamp.info/en/downloads/index.html 26 | [php-osx-downloads]: http://php-osx.liip.ch/ 27 | -------------------------------------------------------------------------------- /_posts/01-05-01-Windows-Setup.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Instalacja w systemie Windows 3 | isChild: true 4 | --- 5 | 6 | ## Instalacja w systemie Windows {#windows_setup_title} 7 | 8 | PHP w systemie Windows można zainstalować na kilka sposobów. Pierwszym z nich jest instalacja 9 | [binariów][php-downloads]. Do wersji 5.3.0 można było korzystać z instalatora .msi, obecnie ten sposób instalacji 10 | nie jest już wspierany. 11 | 12 | Do nauki i lokalnego rozwijania aplikacji opartych o PHP najlepiej użyć serwera WWW wbudowanego w dystrybucję. 13 | Używając go, nie musisz się martwić o jego konfigurację. Jeżeli potrzebujesz czegoś więcej, możesz użyć jednego z 14 | pakietów "all-in-one", który sprawnie zainstaluje dedykowany serwer WWW, PHP oraz bazę danych MysQL. Najbardziej 15 | znanymi rozwiązaniami tego typu są [Web Platform Installer][wpi], [Zend Server CE][zsce], [XAMPP][xampp] oraz 16 | [WAMP][wamp]. Używając ich, pamiętaj o tym, że takie środowisko może różnić się od produkcyjnego, działającego np. na 17 | Linuksie. 18 | 19 | Jeżeli chcesz stworzyć środowisko produkcyjne w systemie Windows, najlepszym rozwiązaniem jest użycie serwera IIS7, 20 | który uznawany jest obecnie za najszybszy i najbardziej stabilny serwer WWW dla Windows. Aby skonfigurować PHP na 21 | serwerze IIS7 możesz użyć pluginu [phpmanager][phpmanager]. Przydatne informacje możesz znaleźć na stronie 22 | [http://php.iis.net][php-iis]. 23 | 24 | Pamiętaj o tym, że rozwijanie aplikacji w systemie znacznie różniącym się od docelowego może prowadzić do problemów 25 | podczas instalacji aplikacji na serwerze produkcyjnym. Jeżeli tworzysz aplikację pod Windowsem, a uruchamiasz ją pod 26 | Linuksem, rozważ możliwość użycia maszyny wirtualnej. W tym celu zainteresuj się projektami [Vagrant][vagrant], a także 27 | [Puppet][puppet] lub [Chef][chef]. 28 | 29 | [php-downloads]: http://windows.php.net 30 | [phpmanager]: http://phpmanager.codeplex.com/ 31 | [wpi]: http://www.microsoft.com/web/downloads/platform.aspx 32 | [zsce]: http://www.zend.com/en/products/zend_server 33 | [xampp]: https://www.apachefriends.org/ 34 | [wamp]: http://www.wampserver.com/en/ 35 | [php-iis]: http://php.iis.net/ 36 | [vagrant]: http://vagrantup.com/ 37 | [puppet]: http://www.puppetlabs.com/ 38 | [chef]: https://www.chef.io/ 39 | -------------------------------------------------------------------------------- /_posts/02-01-01-Code-Style-Guide.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Jak formatować kod 3 | --- 4 | 5 | # Jak formatować kod {#code_style_guide_title} 6 | 7 | Społeczność zgromadzona wokół języka PHP jest relatywnie duża i zróżnicowana, dzięki czemu powstało wiele bibliotek, 8 | frameworków i komponentów. Typową praktyką stosowaną przez programistów PHP jest wybór kilku takich składników i 9 | stworzenie na bazie tego własnego projektu. Stąd istotną sprawą jest to, aby te biblioteki stosowały wspólne konwencje 10 | i styl kodowania. 11 | 12 | Aby wyjść temu problemowi naprzeciw, [Framework Interop Group][fig] (znane także jako 'PHP Standards Group') 13 | wypracowało serię rekomendacji dotyczących stylu kodowania znanych jako [PSR-0][psr0], [PSR-1][psr1], 14 | [PSR-2][psr2] oraz [PSR-4][psr4]. Są one zbiorem konwencji i dobrych praktyk, których powinny trzymać się 15 | programiści tworząc swoje projekty. Już teraz konwencje te stosują m.in. takie projekty jak Drupal, 16 | Zend Framework, CakePHP, phpBB, AWS SDK, FuelPHP, czy Lithium. Oczywiście stosowanie tych zaleceń nie jest 17 | obowiązkowe, równie dobrze możesz tworzyć kod używając swojego własnego stylu. 18 | 19 | Decydując się na używanie PSR, ułatwiasz potencjalnym programistom, którzy będę z Tobą współpracować, zrozumienie 20 | Twojego kodu. Struktura dokumentów PSR jest zorganizowana w ten sposób, że stosowanie PSR-1 wymusza stosowanie PSR-0, 21 | ale nie PSR-2, itd. 22 | 23 | * [Dowiedz się więcej o PSR-0][psr0] 24 | * [Dowiedz się więcej o PSR-1][psr1] 25 | * [Dowiedz się więcej o PSR-2][psr2] 26 | * [Dowiedz się więcej o PSR-4][psr4] 27 | 28 | Aby sprawdzić czy Twój kod spełnia założenia PSR, możesz użyć projektu [PHP_CodeSniffer][phpcs] z użyciem rozszerzenia 29 | [phpcs-psr][phpcs-psr] lub wtyczek do edytorów tekstowych sprawdzających poprawność stylu w locie, 30 | np.: wtyczka [sublime-phpcs][sublime-phpcs] dla edytora Sublime Text. 31 | Aby automatycznie poprawić styl kodu możesz użyć jednego z narzędzi: 32 | 33 | * [PHP Coding Standards Fixer][phpcsfixer] 34 | * [PHP Code Beautifier and Fixer][phpcbf] 35 | 36 | PHP_CodeSniffer użyty w linii poleceń 37 | 38 | phpcs -sw --standard=PSR2 file.php 39 | 40 | wyświetli listę błędów (odstępstw od standardu) wraz z informacją o sposobie usunięcia błędu. 41 | Pakiet PHP_CodeSniffer zawiera drugie polecenie - `phpcbf` - pozwalające automatycznie naprawić wykryte błędy: 42 | 43 | phpcbf -w --standard=PSR2 file.php 44 | 45 | PHP Coding Standards Fixer domyślnie naprawia błędy automatycznie, a z odpowiednimi parametrami 46 | (`--dry-run` i `--diff`) wyświetla podsumowanie proponowanych zmian nie zmieniając plików. 47 | 48 | Kod powinien być pisany z wykorzystaniem angielskiego nazewnictwa. Komentarze powinny być pisane w języku 49 | zrozumiałym dla aktualnych oraz potencjalnych programistów. 50 | 51 | [fig]: http://www.php-fig.org/ 52 | [psr0]: http://www.php-fig.org/psr/psr-0/ 53 | [psr1]: http://www.php-fig.org/psr/psr-1/ 54 | [psr2]: http://www.php-fig.org/psr/psr-2/ 55 | [psr4]: http://www.php-fig.org/psr/psr-4/ 56 | [phpcs]: http://pear.php.net/package/PHP_CodeSniffer/ 57 | [sublime-phpcs]: https://github.com/benmatselby/sublime-phpcs 58 | [phpcs-psr]: https://github.com/klaussilveira/phpcs-psr 59 | [phpcsfixer]: http://cs.sensiolabs.org/ 60 | [phpcbf]: https://github.com/squizlabs/PHP_CodeSniffer/wiki/Fixing-Errors-Automatically 61 | -------------------------------------------------------------------------------- /_posts/03-01-01-Language-Highlights.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Rzut okiem na język 3 | --- 4 | 5 | # Rzut okiem na język {#language_highlights_title} 6 | -------------------------------------------------------------------------------- /_posts/03-02-01-Programming-Paradigms.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Paradygmaty programowania w PHP 3 | isChild: true 4 | --- 5 | 6 | ## Paradygmaty programowania w PHP {#programming_paradigms_title} 7 | 8 | PHP jest językiem, w którym możesz programować na wiele sposobów. Przez ostatnie lata mocno rozwinął swoje możliwości. 9 | W wersji 5.0 (2004) dodano zupełnie nowy model programowania obiektowego, w 5.3 (2009) wprowadzono m.in. [anonimowe 10 | funkcje][anonymous-functions] i [przestrzenie nazw][namespaces], a w 5.4 (2012) - [traity][traits]. 11 | 12 | ### Programowanie obiektowe 13 | 14 | PHP posiada rozbudowany model programowania obiektowego, który obsługuje m.in klasy, klasy abstrakcyjne, interfejsy, 15 | dziedziczenie, konstruktory, klonowanie, czy wyjątki. 16 | 17 | * [Czytaj dalej na temat programowania obiektowego][oop] 18 | * [Dowiedz się więcej na temat traitów][traits] 19 | 20 | ### Programowanie funkcyjne 21 | 22 | PHP od wersji 5.3 wspiera możliwość przypisania funkcji do zmiennej - są to tzw. funkcje anonimowe lub closure'y. 23 | Zarówno funkcje wbudowane, jak i te stworzone przez programistę, mogą być dzięki temu wywołane w sposób dynamiczny, 24 | przekazane jako argumenty wywołania innych funkcji lub nawet przez nie zwracane. 25 | 26 | Funkcje mogą także wywoływać same siebie, czyli działać rekurencyjnie. 27 | 28 | W PHP 5.4 dodano możliwość przypisania closure'a do zakresu obiektu w taki sposób, że mogą one być stosowane zamiennie 29 | z funkcjami anonimowymi praktycznie w każdej sytuacji. 30 | 31 | * Dowiedz sie więcej o [programowaniu funkcyjnym w PHP](/pages/Functional-Programming.html) 32 | * [Artykuł o funkcjach anonimowych][anonymous-functions] 33 | * [Artykuł o klasach typu closure][closure-class] 34 | * [Więcej szczegółów znajdziesz w Closures RFC][closures-rfc] 35 | * [Artykuł o Callables][callables] 36 | * [Artykuł o dynamicznym wywoływaniu funkcji przy użyciu `call_user_func_array`][call-user-func-array] 37 | 38 | ### Metaprogramowanie 39 | 40 | PHP wspiera metaprogramowanie udostępniając mechanizmy takie jak Reflection API i magiczne metody - m.in. `__get()`, 41 | `__set()`, `__call()`, `__callStatic()`, `__clone()`, `__toString()` i `__invoke()`, które umożliwiają programiście 42 | wywołanie danego kodu podczas konkretnych zdarzeń w cyklu życia obiektu. 43 | 44 | * [Artykuł o Reflection API][reflection] 45 | * [Artykuł o magicznych metodach][magic-methods] 46 | 47 | [namespaces]: http://php.net/manual/pl/language.namespaces.php 48 | [overloading]: http://uk.php.net/manual/pl/language.oop5.overloading.php 49 | [oop]: http://www.php.net/manual/pl/language.oop5.php 50 | [anonymous-functions]: http://www.php.net/manual/pl/functions.anonymous.php 51 | [closure-class]: http://php.net/manual/pl/class.closure.php 52 | [callables]: http://php.net/manual/pl/language.types.callable.php 53 | [magic-methods]: http://php.net/manual/pl/language.oop5.magic.php 54 | [reflection]: http://www.php.net/manual/pl/intro.reflection.php 55 | [traits]: http://www.php.net/traits 56 | [call-user-func-array]: http://php.net/manual/pl/function.call-user-func-array.php 57 | [closures-rfc]: https://wiki.php.net/rfc/closures 58 | -------------------------------------------------------------------------------- /_posts/03-03-01-Namespaces.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Przestrzenie nazw 3 | isChild: true 4 | --- 5 | 6 | ## Przestrzenie nazw {#namespaces_title} 7 | 8 | Jak wspomniano wcześniej, społeczność PHP jest tworzona przez niezliczoną ilość programistów. Powoduje to, że może 9 | zdarzyć się sytuacja, w której dwie różne biblioteki użyją klasy o takiej samej nazwie. W takim przypadku pojawi się 10 | problem. 11 | 12 | Naprzeciw temu problemowi wychodzą _przestrzenie nazw_, których działanie można porównać z funkcją katalogów w systemie 13 | plików. Tak samo jak dwa pliki o tej samej nazwie mogą istnieć w dwóch różnych katalogach, klasy o takich samych 14 | nazwach mogą istnieć w różnych przestrzeniach nazw. 15 | 16 | Z tego powodu istotne jest, aby Twój kod był przypisany do własnej przestrzeni nazw. Dzięki temu jego elementy (klasy, 17 | funkcje, czy stałe) nie będą kolidowały z klasami bibliotek, których używasz. Traktuje o tym dokument [PSR-0][psr0]. 18 | 19 | W grudniu 2013 roku PHP-FIG przygotowało kolejny standard: [PSR-4][psr4], który pewnego dnia zastąpi standard [PSR-0][psr0]. 20 | 21 | * [Więcej informacji o przestrzeniach nazw][namespaces] 22 | 23 | [namespaces]: http://php.net/manual/pl/language.namespaces.php 24 | [psr0]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md 25 | [psr4]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md 26 | -------------------------------------------------------------------------------- /_posts/03-04-01-Standard-PHP-Library.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Biblioteka standardowa (SPL) 3 | isChild: true 4 | --- 5 | 6 | ## Biblioteka standardowa (SPL) {#standard_php_library_title} 7 | 8 | Biblioteka standardowa (SPL, Standard PHP Library) jest zbiorem klas i interfejsów, które zapewniają dostępność 9 | typowych struktur danych (stos, kolejka, kopiec, itp) oraz iteratorów zdolnych do trawersowania po nich. W SPL 10 | znajdziesz też funkcje i mechanizmy umożliwiające automatyczne ładowanie klas oraz klasy pomocnicze, przydatne przy 11 | tworzeniu rozwiązań opartych o wzorce projektowe, np. `SplObserer`, `SplSubject`). 12 | 13 | * [Artykuł o SPL][spl] 14 | 15 | [spl]: http://php.net/manual/pl/book.spl.php 16 | -------------------------------------------------------------------------------- /_posts/03-05-01-Command-Line-Interface.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Interfejs CLI 3 | isChild: true 4 | --- 5 | 6 | ## Interfejs CLI (Command Line Interface) {#command_line_interface} 7 | 8 | PHP znajduje zastosowanie głównie przy tworzeniu aplikacji webowych, ale może być również użyteczny jako język 9 | skryptowy, uruchamiany z poziomu konsoli. Dzięki temu można łatwo automatyzować typowe zadania, jak testowanie 10 | jednostkowe, proces deploymentu, czy administrację aplikacją. 11 | 12 | Skrypty uruchamiane z poziomu konsoli mają dostęp do całego kodu Twojej aplikacji i mogą go uruchamiać w ten sam 13 | sposób jak w przypadku wywołania z poziomu serwera WWW. Pamiętaj, aby nie umieszczać skryptów przeznaczonych do 14 | uruchomienia pod konsolą w publicznej części Twojego projektu. 15 | 16 | Spróbuj uruchomić następujące polecenie z poziomu linii poleceń: 17 | 18 | {% highlight bash %} 19 | > php -i 20 | {% endhighlight %} 21 | 22 | Twoim oczom powinna ukazać się pełna konfiguracja PHP, zbliżona do tej, którą zwraca funkcja [`phpinfo`][phpinfo]. 23 | 24 | Inną ciekawą opcją jest `-a` - umożliwia ona uruchomienie interaktywnej konsoli PHP, podobnej do tej z Ruby'ego, czy 25 | Pythona. 26 | 27 | Aby zapoznać się z pełną listą opcji interfejsu konsolowego, zajrzyj na [tę stronę][cli-options]. 28 | 29 | Jeżeli argumentem wywołania polecenia `php` będzie plik z kodem źródłowym, zostanie on uruchomiony. Uruchamiając skrypt 30 | z poziomu konsoli otrzymujesz dostęp do dwóch zmiennych - `$argc` i `$argv`. Pierwsza z nich jest liczbą naturalną, 31 | reprezentującą ilość przekazanych argumentów wywołania, a druga tablicą z ich wartościami. Ponadto istnieje możliwość 32 | zwrócenia kodu wyjścia, aby poinformować powłokę, czy skrypt wykonał się poprawnie. Więcej informacji na temat kodów 33 | wyjścia znajdziesz [tutaj][exit-codes]. 34 | 35 | Poniżej znajdziesz kod skryptu drukującego napis "Witaj, $imie" z możliwością podania imienia przez linię poleceń. Plik 36 | z przykładu nazywa się `hello.php`. 37 | 38 | {% highlight php %} 39 | php hello.php 52 | Usage: php hello.php [imię] 53 | > php hello.php Marek 54 | Witaj, Marek! 55 | {% endhighlight %} 56 | 57 | 58 | * [Jak uruchamiać skrypty PHP z linii poleceń][php-cli] 59 | * [Jak skonfigurować PHP w systemie windows, aby móc uruchamiać skrypty z linii poleceń][php-cli-windows] 60 | 61 | [phpinfo]: http://php.net/manual/pl/function.phpinfo.php 62 | [cli-options]: http://www.php.net/manual/pl/features.commandline.options.php 63 | [argc]: http://php.net/manual/pl/reserved.variables.argc.php 64 | [argv]: http://php.net/manual/pl/reserved.variables.argv.php 65 | [php-cli]: http://php.net/manual/pl/features.commandline.php 66 | [php-cli-windows]: http://www.php.net/manual/pl/install.windows.commandline.php 67 | [exit-codes]: http://www.gsp.com/cgi-bin/man.cgi?section=3&topic=sysexits -------------------------------------------------------------------------------- /_posts/03-06-01-XDebug.md: -------------------------------------------------------------------------------- 1 | --- 2 | isChild: true 3 | --- 4 | 5 | ## XDebug {#xdebug_title} 6 | 7 | Jednym z najbardziej użytecznych narzędzi podczas programowania jest debugger. Debugger pozwala na śledzenie 8 | wykonywania kodu i monitorowanie zawartości stosu. W PHP dostępny jest debugger o nazwie XDebug. Można go używać z 9 | poziomu IDE do śledzenia wykonywania kodu, a także wykorzystywać do profilowania aplikacji za pomocą KCacheGrind, czy 10 | tworzenia raportów pokrycia kodu testami w PHPUnit. 11 | 12 | Debugger przydaje się tam, gdzie ręczny debug za pomocą funkcji print_r/var_dump nie daje rady. 13 | 14 | [Instalacja XDebuga][xdebug-install] może okazać się dość skomplikowana. Najważniejszą funkcjonalnością jest zdalne 15 | debuggowanie ("Remote Debugging") - przydaje się, gdy tworzysz kod lokalnie, a testujesz go na wirtualnej maszynie, bądź 16 | na zdalnym serwerze. 17 | 18 | Aby skorzystać z tej funkcji, należy zmodyfikować konfigurację vhosta w poniższy sposób: 19 | 20 | php_value xdebug.remote_host "?.?.?.?" 21 | php_value xdebug.remote_port "9000" 22 | 23 | Wartości dyrektyw `remote_host` i `remote_port` powinny wskazywać na adres IP lokalnego komputera i port na którym 24 | nasłuchuje IDE. Po załadowaniu adresu z dodatkowym parametrem `XDEBUG_SESSION_START` o wartości `1` 25 | (np. http://your-website.example.com/index.php?XDEBUG_SESSION_START=1), IDE przechwyci bieżący stan wykonywanego 26 | skryptu umożliwiając kontrolę jego wykonywania. To bardzo ułatwia debuggowanie aplikacji. 27 | 28 | * [Czytaj dalej o XDebug][xdebug-docs] 29 | 30 | [xdebug-docs]: http://xdebug.org/docs/ 31 | [xdebug-install]: http://xdebug.org/docs/install 32 | -------------------------------------------------------------------------------- /_posts/04-01-01-Dependency-Management.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Zarządzanie zależnościami 3 | --- 4 | 5 | # Zarządzanie zależnościami {#dependency_management_title} 6 | 7 | PHP posiada tysiące bibliotek, frameworków i komponentów. Tworząc swój projekt wybierzesz prawdopodobnie kilka z nich 8 | - będą to jego zależności. Przez wiele lat PHP nie posiadał sprawnie działającego sposobu na zarządzanie zależnościami. 9 | Nawet jeżeli udało Ci się zestawić razem potrzebne Ci biblioteki, musiałeś ręcznie zadbać o ich dołączenie do projektu. 10 | Nigdy więcej. 11 | 12 | PHP dysponuje dwoma niezależnymi systemami pakietów. Są nimi Composer i PEAR. Zastanawiasz się pewnie który wybrać. 13 | Otóż wszystko zależy od tego w jaki sposób chcesz go użyć. 14 | 15 | * Jeżeli potrzebujesz stworzyć zależności dla konkretnego projektu - użyj **Composera**. 16 | * Jeżeli potrzebujesz zarządzać zależnościami dla całej instalacji PHP - użyj **PEARa**. 17 | 18 | Innymi słowy, pakiety Composera będą dostępne jedynie w projekcie, dla którego je przygotujesz, podczas gdy biblioteki 19 | PEARa będą dostępne dla wszystkich aplikacji w obrębie instalacji PHP. Mimo, że PEAR wydaje się być łatwiejszym 20 | podejściem, istnieje wiele przesłanek, aby zarządzać swoimi zależnościami per projekt, czyli używając Composera. 21 | -------------------------------------------------------------------------------- /_posts/04-02-01-Composer-and-Packagist.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Composer i Packagist 3 | isChild: true 4 | --- 5 | 6 | ## Composer i Packagist {#composer_and_packagist_title} 7 | 8 | Composer jest **genialnym** systemem wspomagającym zarządzanie zależnościami aplikacji w PHP. Wystarczy jeżeli 9 | wylistujesz swoje zależności w pliku `composer.json`, a narzędzie to, przy użyciu kilku prostych poleceń, automagicznie 10 | ściągnie odpowiednie wersje bibliotek i ich zależności oraz odpowiednio skonfiguruje autoloadera. 11 | 12 | Za pomocą Composera można zainstalować wiele znanych bibliotek. Ich listę znajdziesz na stronie projektu [Packagist][1] 13 | - oficjalnego repozytorium bibliotek kompatybilnych z tym systemem. 14 | 15 | ### Instalacja Composera 16 | 17 | Composera możesz zainstalować lokalnie (w katalogu Twojego projektu) lub globalnie (np. w /usr/local/bin). Aby móc użyć 18 | tego narzędzia, wejdź do jego katalogu swojego projektu i wydaj polecenie: 19 | 20 | curl -s https://getcomposer.org/installer | php 21 | 22 | Polecenie to ściągnie do bieżącego katalogu plik `composer.phar`, który będziesz mógł uruchomić za pomocą PHP, aby 23 | zarządzać zależnościami. Pamiętaj, że przekierowanie zawartości strony bezpośrednio do interpretera PHP może nie być 24 | bezpieczne - przed wykonaniem tego polecenia zapoznaj się z kodem znajdującym się pod adresem 25 | http://getcomposer.org/installer. 26 | 27 | Aby zainstalować Composera dla wszystkich użytkowników, wystarczy jeżeli przeniesiesz ściągnięty plik `composer.phar` 28 | do współdzielonego katalogu, np. `/usr/local/bin`, zmieniając jego nazwę na `composer` 29 | (`sudo mv composer.phar /usr/local/bin/composer`). 30 | 31 | ### Ręczna instalacja Composera 32 | 33 | Ręczna instalacja Composera jest bardziej skomplikowanym procesem, gdyż sam musisz sprawdzić swój system, aby 34 | upewnić się, że spełnia on wymagania stawiane przez tę aplikację. Instalacja automatyczna sprawdza: 35 | - czy używasz odpowiedniej wersji PHP, 36 | - czy rozszerzenie phar jest zainstalowane, 37 | - czy uprawnienia do katalogów są odpowiednie, 38 | - czy nie zostały zainstalowane problematyczne rozszerzenia PHP, 39 | - oraz czy plik `php.ini` zawiera odpowiednie ustawienia. 40 | 41 | Aby pobrać Composera ręcznie, wykonaj następujące polecenia: 42 | 43 | curl -s https://getcomposer.org/composer.phar -o $HOME/local/bin/composer 44 | chmod +x $HOME/local/bin/composer 45 | 46 | Ścieżka `$HOME/local/bin` (lub dowolna inna którą wybierzesz) powinna znajdować się w zmiennej środowiskowej $PATH, 47 | dzięki czemu będziesz miał możliwość skorzystania z polecenia `composer` zamiast `php composer.phar`. 48 | 49 | ### Jak definiować i instalować zależności 50 | 51 | Najpierw stwórz plik `composer.json` w katalogu głównym swojego projektu i umieść w nim odpowiednie wpisy. Poniższy 52 | przykład demonstruje jak przy użyciu Composera zainstalować projekt [Twig][2]. W pliku `composer.json` umieść poniższą 53 | zawartość: 54 | 55 | { 56 | "require": { 57 | "twig/twig": "1.8.*" 58 | } 59 | } 60 | 61 | A następnie, będąc w tym samym katalogu, uruchom poniższe polecenie: 62 | 63 | php composer.phar install 64 | 65 | Efektem działania będzie ściągnięcie odpowiedniej wersji projektu Twig do katalogu `vendors/` oraz odpowiednie 66 | skonfigurowanie autoloadera. Aby z niego skorzystać, musisz dołączyć plik `vendor/autoload.php` do swojego skryptu: 67 | 68 | {% highlight php %} 69 | upload->get_error()`, abyś sprawdził sobie co poszło nie tak. Problemem jest to, że musisz o tym wiedzieć lub 17 | szukać rozwiązania w dokumentacji, zamiast otrzymać jasny komunikat w postaci wyjątku. 18 | 19 | Innym problemem jest fakt, że zwykle w przypadku błędu aplikacje wyświetlają komunikat błędu na stronie i kończą 20 | wykonywanie skryptu przez `exit`, przez co developerzy tracą możliwość dynamicznego obsłużenia takiego przypadku. 21 | Naprzeciw temu wychodzą wyjątki, które informują dewelopera o problemie i pozwalają mu podjąć odpowiednie kroki. 22 | Przykład: 23 | 24 | {% highlight php %} 25 | subject('Mój temat'); 28 | $email->body('Jak się masz?'); 29 | $email->to('guy@example.com', 'Ktoś'); 30 | 31 | try 32 | { 33 | $email->send(); 34 | } 35 | catch(Fuel\Email\ValidationFailedException $e) 36 | { 37 | // Walidacja danych wejściowych nie powiodła się 38 | } 39 | catch(Fuel\Email\SendingFailedException $e) 40 | { 41 | // Aplikacja nie była w stanie wysłać maila 42 | } 43 | {% endhighlight %} 44 | 45 | ### Wyjątki w SPL 46 | 47 | Wyjątek sam w sobie nie ma żadnego konkretnego znaczenia i najprostszym sposobem na zmianę tego stanu rzeczy jest 48 | nadanie mu nazwy: 49 | 50 | {% highlight php %} 51 | format('Y-m-d') . "\n"; 23 | {% endhighlight %} 24 | 25 | Operacje arytmetyczne na obiekcie `DateTime` najłatwiej wykonuje się za pomocą klasy `DateInterval`. `DateTime` posiada 26 | metody `add()` i `sub()`, które przyjmują obiekt klasy `DateInterval` jako argument - dzięki temu możesz zapomnieć o 27 | problemach związanych ze strefami czasowymi oraz istnieniem czasu letniego i zimowego. Przykładowo, aby obliczyć 28 | interwał czasu między dwiema datami, możesz użyć metody `diff()`. Zwraca ona obiekt `DateInterval`, który bez zbędnych 29 | obliczeń zamienisz na zrozumiały dla użytkownika ciąg znaków. 30 | 31 | {% highlight php %} 32 | add(new \DateInterval('P1M6D')); 36 | 37 | $diff = $end->diff($start); 38 | echo "Różnica: " . $diff->format('%m miesiąc, %d dni (razem: %a dni)') . "\n"; 39 | // Różnica: 1 miesiąc, 6 dni (razem: 37 dni) 40 | {% endhighlight %} 41 | 42 | Stosując obiekty `DateTime` możesz używać zwykłych operatorów porównania: 43 | {% highlight php %} 44 | format('m/d/Y') . " "; 63 | } 64 | {% endhighlight %} 65 | 66 | * [Strona w manualu na temat `DateTime`][datetime] 67 | * [dostępne opcje formatowania dat w PHP][dateformat] 68 | 69 | [datetime]: http://www.php.net/manual/book.datetime.php 70 | [dateformat]: http://www.php.net/manual/function.date.php 71 | -------------------------------------------------------------------------------- /_posts/05-03-01-Design-Patterns.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Wzorce projektowe 3 | isChild: true 4 | --- 5 | 6 | ## Wzorce projektowe {#design_patterns_title} 7 | 8 | Wzorce projektowe bywają bardzo pomocne podczas tworzenia aplikacji. Dzięki ich użyciu, prościej jest zarządzać swoim 9 | kodem, a innym deweloperom - zrozumieć jak działają jego wewnętrzne mechanizmy. 10 | 11 | Wiele popularnych frameworków PHP implementuje wzorce projektowe. Jeżeli używasz któregoś z nich w swojej aplikacji, 12 | do Ciebie należy jedynie podążanie za nimi w kodzie swojej aplikacji. Jeżeli budujesz coś własnego od zera, będziesz 13 | musiał znaleźć i dopasować wzorce, które odpowiadają strukturze Twojej aplikacji. 14 | 15 | * Więcej na temat [wzorców projektowych](/pages/Design-Patterns.html) 16 | -------------------------------------------------------------------------------- /_posts/06-01-01-Databases.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Bazy danych 3 | --- 4 | 5 | # Bazy danych {#databases_title} 6 | 7 | Tworząc aplikacje webowe, wielokrotnie staniesz przed koniecznością przechowania pewnych informacji. Służą do tego 8 | bazy danych. PHP wspiera wiele różnych silników baz danych. Zalecanym sposobem komunikacji z bazami danych _do wersji 9 | 5.1_ były natywne sterowniki, takie jak [mysql][mysql], [mysqli][mysqli], [pgsql][pgsql], itd. 10 | 11 | Sterowniki te sprawują się dobrze, o ile łączysz się z tylko jednym rodzajem bazy danych, np. MySQL, czy MSSQL, gdyż 12 | każdy z nich posiada inne API, a nauka każdego z nich szybko może się okazać bezsensownym nakładem czasu. Dodatkowo, 13 | sterownik mysql nie jest już aktywnie rozwijany i od wersji PHP 5.4.0 ma status "Long term deprecation", co oznacza, że 14 | wkrótce może zostać usunięty z PHP. Jeżeli obecnie używasz w swojej aplikacji funkcji `mysql_connect()`, czy 15 | `mysql_query()`, zapewne wkróce staniesz przed problemem przepisania tej części. Aby tego uniknąć, zaleca się 16 | stosowanie obiektowych rozszerzeń, takich jak mysqli lub PDO. 17 | 18 | * [Jak wybrać API do MySQL](http://php.net/manual/en/mysqlinfo.api.choosing.php) 19 | 20 | ## PDO 21 | 22 | PDO jest bazodanową warstwą abstrakcji dostępną od PHP 5.1.0, która dostarcza obiektowy interfejs do komunikacji z 23 | wieloma silnikami baz danych. PDO nie tłumaczy Twoich zapytań SQL ani nie emuluje brakujących funkcjonalności; jest 24 | natomiast biblioteką umożliwiającą łączenie się do wszystkich obsługiwanych przez siebie baz danych przez jedno wspólne 25 | API, co jest doskonałym rozwiązaniem dla aplikacji w których osoba instalująca ją decyduje o typie silnika. 26 | 27 | Co ważne, PDO pozwala na przekazywanie parametrów do zapytania SQL bezpośrednio z żądania ($_GET, $_POST). Nie musisz 28 | martwić się już o ataki SQL injection, gdyż biblioteka w odpowiedni sposób zabezpieczy ich wartości, aby nie były 29 | niebezpieczne. Dzieje się to dzięki tzw. "prepared statements" (`PDO::prepare()`) i wstrzykiwaniu parametrów przy 30 | użyciu metody `bindParam()`. 31 | 32 | Spójrzmy na typowy przykład. Twój skrypt otrzymuje numeryczne ID w parametrze GET. To ID uzywane jest później w 33 | zapytaniu SQL, aby wyciągnąć z bazy informacje na temat konkretnego rekordu. Poniżej przedstawiony jest kod, który 34 | nie korzysta z "prepared statements": 35 | 36 | {% highlight php %} 37 | query("SELECT name FROM users WHERE id = " . $_GET['id']); // <-- NIE! 40 | {% endhighlight %} 41 | 42 | Cóż, ten kod jest tragiczny. Parametr `id` wstrzykiwany jest do zapytania SQL prosto z żądania (`$_GET['id']`), co 43 | umożliwia wykonanie ataktu SQL injection, a w efekcie wykonanie dowolnego zapytania SQL na Twojej bazie danych. Aby 44 | tego uniknąć, powinieneś zabezpieczyć wartość tego parametru. Dzięki `bindParam()`, operacja zabezpieczenia wykona się 45 | automatycznie: 46 | 47 | {% highlight php %} 48 | prepare('SELECT name FROM users WHERE id = :id'); 51 | $stmt->bindParam(':id', $_GET['id'], PDO::PARAM_INT); //<-- Automatyczne zabezpieczenie wartości parametru 52 | $stmt->execute(); 53 | {% endhighlight %} 54 | 55 | To jest poprawny kod. PDO przy użyciu metody `bindParam()` zabezpiecza w odpowiedni wartość parametru uniemożliwiając 56 | wykonanie ataku SQL injection. 57 | 58 | * [Więcej informacji o PDO][1] 59 | 60 | ## Warstwy abstrakcji 61 | 62 | Sporo frameworków posiada własną warstwę abstrakcji bazy danych. Niektóre z nich bazują na PDO, inne nie. Często 63 | emulują funkcjonalności niedostępne w danym silniku poprzez opakowywanie zapytań w metody. Jest to oczywiście 64 | pewien narzut czasowy, ale jeżeli Twoja aplikacja ma działać jednocześnie np. na MySQL, PostgreSQL i SQLite, czasem 65 | przejrzystość kodu jest ważniejsza niż niewielki narzut. 66 | 67 | Niektóre z tych warstw zostały napisane z uwzględnieniem standardu przestrzeni nazw `PSR-0`, dzięki czemu mogą być 68 | użyte w dowolnej aplikacji napisanej w PHP. 69 | 70 | * [Doctrine2 DBAL][2] 71 | * [ZF2 Db][4] 72 | * [ZF1 Db][3] 73 | 74 | [1]: http://www.php.net/manual/pl/book.pdo.php 75 | [2]: http://www.doctrine-project.org/projects/dbal.html 76 | [3]: http://framework.zend.com/manual/en/zend.db.html 77 | [4]: http://packages.zendframework.com/docs/latest/manual/en/index.html#zend-db 78 | 79 | [mysql]: http://pl.php.net/mysql 80 | [mysqli]: http://pl.php.net/mysqli 81 | [pgsql]: http://pl.php.net/pgsql 82 | -------------------------------------------------------------------------------- /_posts/07-01-01-Security.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Bezpieczeństwo 3 | --- 4 | 5 | # Bezpieczeństwo {#security_title} 6 | -------------------------------------------------------------------------------- /_posts/07-02-01-Web-Application-Security.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Bezpieczeństwo aplikacji webowych 3 | isChild: true 4 | --- 5 | 6 | ## Bezpieczeństwo aplikacji webowych {#web_application_security_title} 7 | 8 | Są na świecie dranie, którzy chcieliby wykorzystać Twoją aplikację do niecnych celów. Jako deweloper, powinieneś być 9 | świadomy zagrożeń, które czyhają z ich strony i w odpowiedni sposób zabezpieczyć swoją aplikację, aby ich uniknąć. Na 10 | szczęście dobrzy ludzie z projektu [The Open Web Application Security Project][1] (OWASP) przygotowali obszerną listę 11 | potencjalnych zagrożeń wynikających z dostępności Twojej aplikacji w Internecie wraz z informacjami o sposobach 12 | zabezpieczenia przez nimi. Jest to lektura obowiązkowa dla każdego dewelopera PHP chcącego pisać bezpieczne aplikacje 13 | webowe. 14 | 15 | * [Przeczytaj "OWASP Security Guide"][2] 16 | 17 | [1]: https://www.owasp.org/ 18 | [2]: https://www.owasp.org/index.php/Guide_Table_of_Contents 19 | -------------------------------------------------------------------------------- /_posts/07-03-01-Password-Hashing-with-Bcrypt.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Kodowanie haseł za pomocą Bcrypt 3 | isChild: true 4 | --- 5 | 6 | ## Kodowanie haseł za pomocą Bcrypt {#password_hashing_with_bcrypt_title} 7 | 8 | Każdy programista napisze pewnego dnia aplikację, w której jedną z funkcjonalności będzie możliwość zalogowania się 9 | użytkownika. W takiej aplikacji, dane autoryzacyjne (login i hasło) zwykle przechowywane są w bazie danych, aby za ich 10 | pomocą zautentykować użytkownika. W takim przypadku bardzo istotną kwestią jest odpowiednie zakodowanie (zahashowanie) 11 | zapisanych haseł, aby uniknąć sytuacji, w której po ataku hackerskim na bazę danych, konta Twoich użytkowników 12 | pozostaną dostępne włamywaczom. 13 | 14 | Na szczęście w PHP wbudowany jest prosty, acz skuteczny mechanizm hashowania dowolnych danych - Bcrypt. Po zastosowaniu 15 | go, otrzymujemy skrót, na podstawie którego nie ma możliwości odgadnięcia pierwotnej postaci zakodowanego ciągu znaków. 16 | 17 | w PHP dostępnych jest kilka bibliotek bazujących ba Bcyrpt, których móżesz użyć w swojej aplikacji. 18 | 19 | * [Artykuł "How to Safely Store a Password" na stronie Coda Hale][3] 20 | * [Strona projektu PHPass][4] 21 | 22 | [3]: http://codahale.com/how-to-safely-store-a-password/ 23 | [4]: http://www.openwall.com/phpass/ 24 | -------------------------------------------------------------------------------- /_posts/07-04-01-Data-Filtering.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Filtrowanie danych 3 | isChild: true 4 | --- 5 | 6 | ## Filtrowanie danych {#data_filtering_title} 7 | 8 | Nigdy, przenigdy nie ufaj zewnętrznym danym wprowadzonym do Twojego kodu. Zawsze waliduj i zabezpieczaj je przed 9 | użyciem. Możesz użyć do tego funkcji `filter_var()` i `filter_input()`, które pomagają w tych czynnościach - potrafią 10 | przykładowo w prosty sposób sprawdzić poprawność składniową wprowadzonego przez użytkownika adresu e-mail. 11 | 12 | Zewnętrzne dane mogą znaleźć się wszędzie: głównym ich źródłem są tablice `$_GET` i `$_POST` zawierające parametry 13 | żądania. Niektóre wartości w tablicy `$_SERVER` pochodzą wprost z nagłówków, które wysyła użytkownik, czy 14 | `fopen('php://input', 'r')` - ciało żądania HTTP. Pamiętaj, że zewnętrzne dane to nie tylko dane z formularzy 15 | wysłanych przez użytkownika. Pliki, które ściągasz, dane sesji, ciasteczka, czy nawet dane z zewnętrznych 16 | webservice'ów powinny być traktowane jako dane, którym nie można ufać. 17 | 18 | Z uwagi na to, że zewnętrzne dane mogą być przechowywane w bazach danych, należy pamiętać o tym, żeby przy ich odczycie 19 | również zadbać o ich zabezpieczenie. Za każdym razem, gdy próbujesz użyć takich danych zadaj sobie pytanie, czy są one 20 | odpowiednio zabezpieczone i czy można im ufać. 21 | 22 | Sposób zabezpieczania zewnętrznych danych zależy od sposobu ich użycia. Przykładowo gdy chcesz użyć danych pochodzących 23 | od użytkownika w HTML'u, musisz zadbać o usunięcie bądź zamianę znaczników sterujących, takich jak '<', '>' na 24 | odpowiednie encje HTML, gdyż w przeciwnym razie odpowiednio spreparowany ciąg znaków może uruchomić skrypt JS, co może 25 | być bardzo opłakane w skutkach - może przykładowo pomóc w przejęciu sesji użytkownika. Taki rodzaj ataku to XSS 26 | (Cross-Site Scripting). 27 | 28 | Innym przykładem jest przekazywanie danych od użytkownika jako fragment lub całość komendy do wykonania z poziomu linii 29 | poleceń. Nieodpowiednie zabezpieczenie takich danych przed użyciem w ten sposób może doprowadzić do wykonania 30 | niepożądanego polecenia, co może być poważnym zagrożeniem bezpieczeństwa aplikacji i/lub systemu na którym ona działa. 31 | Aby bezpiecznie przekazać takie dane do wiersza poleceń, zabezpiecz je za pomocą funkcji `escapeshellarg()`. 32 | 33 | Niebezpieczeństwo może czyhać również tam, gdzie za pomocą danych z zewnątrz ustalasz ścieżkę w systemie plików. 34 | Atakujący może wykorzystać to poprzez odpowiednią zmianę przekazanych wartości. Twoja aplikacja wczyta wtedy inny plik 35 | niż powinna, co może spowodować wyciek prywatnych danych lub pomóc w przeprowadzeniu innego ataku. Aby zabezpieczyć się 36 | przed tym, usuwaj "/", ".." i tzw. "[null bytes][6]" ze zmiennych przy użyciu których ustalasz ścieżkę pliku do 37 | wczytania. 38 | 39 | * [Dowiedz się więcej na temat filtrowania danych][1] 40 | * [Dowiedz się więcej na temat funkcji `filter_var()`][4] 41 | * [Dowiedz się więcej na temat funkcji `filter_input()`][5] 42 | * [Dowiedz się więcej na temat "null bytes"][6] 43 | 44 | ### Zabezpieczanie danych z zewnątrz (escaping) 45 | 46 | Dane pochodzące z zewnątrz mogą posiadać niebezpieczne znaki. Aby bezpiecznie się nimi posługiwać w aplikacji (np. aby 47 | bezpiecznie skorzystać z danych wejściowych w HTML'u bądź zapytaniu SQL), należy się ich pozbyć. Proces ten nazywany 48 | jest escapingiem. 49 | 50 | W przypadku zapytań SQL najlepszym sposobem na automatyczne zabezpieczenie się przez niebezpiecznymi znakami jest 51 | użycie PDO, które zrobi to za Ciebie. Jeżeli chodzi o HTML, częstym wyzwaniem jest konieczność dopuszczenia kilku 52 | wybranych tagów, aby umożliwić użytkownikowi proste formatowanie wpisanego tekstu. W takim przypadku jednym z wyjść 53 | jest użycie formatowania Markdown lub BBCode, bądź bibliotek takich jak [HTML Purifier][html-purifier]. 54 | 55 | [Lista filtrów escape'ujących][2] 56 | 57 | ### Walidacja 58 | 59 | Dzięki walidacji możesz upewnić się, że wprowadzone przez użytkownika dane są tym, czego się spodziewasz. Dobrym 60 | przykładem jest walidacja danych takich jak adres e-mail, numer telefonu, czy wiek, wprowadzonych w formularzu 61 | rejestracji. 62 | 63 | [Lista filtrów walidujących][3] 64 | 65 | [1]: http://www.php.net/manual/pl/book.filter.php 66 | [2]: http://www.php.net/manual/pl/filter.filters.sanitize.php 67 | [3]: http://www.php.net/manual/pl/filter.filters.validate.php 68 | [4]: http://php.net/manual/pl/function.filter-var.php 69 | [5]: http://www.php.net/manual/pl/function.filter-input.php 70 | [6]: http://php.net/manual/pl/security.filesystem.nullbytes.php 71 | [html-purifier]: http://htmlpurifier.org/ 72 | -------------------------------------------------------------------------------- /_posts/07-05-01-Configuration-Files.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Pliki konfiguracyjne 3 | isChild: true 4 | --- 5 | 6 | ## Pliki konfiguracyjne {#configuration_files_title} 7 | 8 | Jeżeli Twoja aplikacja używa zewnętrznych plików konfiguracyjnych, pamiętaj, że nie powinny być one dostępne dla 9 | zewnętrznego świata. Zalecane jest użycie jednego z poniższych sposobów ich zabezpieczenia: 10 | 11 | - Trzymaj pliki konfiguracyjne poza DocumentRoot'em, dzięki czemu nie będą dostępne przez serwer WWW. 12 | - Jeżeli musisz przechowywać je w DocumentRoot'cie, zmień ich rozszerzenie na `.php`. W tym przypadku, nawet jeżeli 13 | skrypt zostanie wywołany bezpośrednio, jego zawartość nie będzie zwrócona do przeglądarki w oryginalnej formie. 14 | - Zawartość plików konfiguracyjnych powinna zostać odpowiednio zabezpieczona - albo poprzez ich szyfrowanie, albo przy 15 | użyciu zabezpieczeń oferowanych przez system plików (zmiana właściciela i/lub praw dostepu). 16 | -------------------------------------------------------------------------------- /_posts/07-06-01-Register-Globals.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: register_globals 3 | isChild: true 4 | --- 5 | 6 | ## register_globals {#register_globals_title} 7 | 8 | UWAGA: 9 | Od wersji PHP 5.4.0 dyrektywa `register_globals` została usunięta i nie ma możliwości korzystania niej. Jej dostępność 10 | w wersjach >= 5.4.0 ogranicza się do wyświetlenia odpowiedniego komunikatu w przypadku omyłkowego użycia. 11 | 12 | W poprzednich wersjach PHP, po włączeniu dyrektywy `register_globals`, zmienne pochodzące od użytkownika (m.in. 13 | `$_POST`, `$_GET` i `$_REQUEST`) były "spłaszczane" do zwykłych zmiennych dostępnych w globalnej zakresie widoczności. 14 | To w łatwy sposób mogło prowadzić do problemów bezpieczeństwa, gdyż aplikacja nie była w stanie stwierdzić skąd 15 | pochodzą wartości poszczególnych zmiennych. 16 | 17 | Przykładowo, po włączeniu `register_globals`, zmienna `$_GET['foo']` byłaby dostępna jako $foo, co może nadpisać inną 18 | zmienną $foo i powodować problemy. 19 | 20 | Podsumowując, jeżeli używasz PHP < 5.4.0 __upewnij się__, że dyrektywa `register_globals` ma wartość __off__. 21 | 22 | * [Artykuł na ten temat w manualu](http://www.php.net/manual/pl/security.globals.php) -------------------------------------------------------------------------------- /_posts/07-07-01-Error-Reporting.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Raportowanie błędów 3 | isChild: true 4 | --- 5 | 6 | ## Raportowanie błędów {#error_reporting_title} 7 | 8 | Wyświetlanie błędów jest pomocne przy szukaniu problematycznych miejsc w Twojej aplikacji, ale ma jeden poważny minus: 9 | eksponuje systemowe, być może kluczowe z punktu widzenia bezpieczeństwa, informacje całemu światu. Pamiętaj o tym, że 10 | środowisko produkcyjne (live) powinno być skonfigurowane pod tym względem inaczej niż deweloperskie. 11 | 12 | ### Środowisko deweloperskie 13 | 14 | W środowisku deweloperskim lub testowym wyświetlanie komunikatów błędów może być 15 | przydatne podczas śledzenia problemów z aplikacją. W tym środowisku powinieneś skonfigurować raportowanie błędów w ten 16 | sposób: 17 | 18 | - display_errors: On 19 | - error_reporting: -1 20 | - log_errors: On 21 | 22 | Za [php.net](http://pl1.php.net/manual/pl/function.error-reporting.php): 23 | 24 | > Passing in the value -1 will show every possible error, even when new levels and constants are added in future PHP versions. The E_ALL constant also behaves this way as of PHP 5.4. 25 | 26 | Poziom raportowania `E_STRICT` jest dostępny od wersji 5.3.0 nie będąc częścią poziomu `E_ALL`. W wersji 5.4.0 27 | zmieniono to zachowanie i `E_STRICT` jest częścią `E_ALL`. Co oznacza to dla programisty? To, że jeżeli potrzebuje 28 | wyświetlać wszystkie możliwe błędy w 5.3.0, należy użyć wartości `-1` lub `E_ALL | E_STRICT`. 29 | 30 | Podsumowując: 31 | 32 | * dla PHP < 5.3 - `-1` lub `E_ALL` 33 | * dla PHP = 5.3 - `-1` lub `E_ALL | E_STRICT` 34 | * dla PHP > 5.3 - `-1` lub `E_ALL` 35 | 36 | ### Środowisko produkcyjne 37 | 38 | W środowisku produkcyjnym wszystkie błędy powinny być ukryte i logowane do zewnętrznego pliku. W tym 39 | środowisku powinieneś skonfigurować raportowanie błędów w ten sposób: 40 | 41 | - display_errors: Off 42 | - error_reporting: E_ALL 43 | - log_errors: On 44 | 45 | Aby uzyskać więcej informacji na temat funkcji kontrolujących sposób raportowania błędów, zajrzyj do manuala: 46 | 47 | * [Error_reporting](http://www.php.net/manual/pl/errorfunc.configuration.php#ini.error-reporting) 48 | * [Display_errors](http://www.php.net/manual/pl/errorfunc.configuration.php#ini.display-errors) 49 | * [Log_errors](http://www.php.net/manual/pl/errorfunc.configuration.php#ini.log-errors) -------------------------------------------------------------------------------- /_posts/08-01-01-Testing.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Testowanie 3 | --- 4 | 5 | # Testowanie {#testing_title} 6 | 7 | Pisanie testów automatycznych do dobra praktyka zwiększająca prawdopodobieństwo, że Twoja aplikacja będzie dobrze 8 | zbudowana. Uruchamiając testy automatyczne podczas kodowania upewniasz się, że zmiany, które wprowadzasz nie psują 9 | innych rejonów aplikacji. Korzystaj z nich, jeżeli możesz. 10 | 11 | Istnieje kilka sposobów automatycznego testowania kodu aplikacji napisanych w PHP. Każdy z nich ma na celu zredukowanie 12 | nakładu na ręczne testowanie, co oczywiście przekłada się na mniejsze zespoły testowe, a w efekcie do ograniczenia 13 | kosztów projektu. -------------------------------------------------------------------------------- /_posts/08-02-01-Test-Driven-Development.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Test-Driven Development 3 | isChild: true 4 | --- 5 | 6 | ## Test-Driven Development {#test_driven_development_title} 7 | 8 | Cytując [Wikipedię](http://pl.wikipedia.org/wiki/Test-driven_development): 9 | 10 | > Test-driven development (TDD) jest techniką tworzenia oprogramowania, która polega na wielokrotnym powtarzaniu kilku kroków: najpierw programista pisze automatyczny test sprawdzający dodawaną funkcjonalność. Test w tym momencie nie powinien się udać. Później następuje implementacja funkcjonalności. W tym momencie wcześniej napisany test powinien się udać. W ostatnim kroku, programista dokonuje refaktoryzacji napisanego kodu, żeby spełniał on oczekiwane standardy. Technika została stworzona przez Kenta Becka. Można jej też używać do poprawiania istniejącego kodu. 11 | 12 | Istnieje kilka sposób testowania aplikacji, których możesz użyć podczas rozwijania swojej aplikacji. 13 | 14 | ### Testy jednostkowe 15 | 16 | Testy jednostkowe są techniką, która umożliwia sprawdzenie, czy funkcje, klasy i metody działają tak jak powinny - 17 | przez cały cykl ich życia. Sprawdzanie ich wewnętrznej logiki odbywa się poprzez ich wywoływanie z różnymi parametrami 18 | wejściowymi i badaniu ich odpowiedzi za pomocą odpowiednich asercji. Jeszcze dokładniejsze wyniki testów oraz bardziej 19 | kompletne pokrycie kodu testami można uzyskać dzięki wstrzykiwaniu zależności oraz korzystaniu z "mocków". 20 | 21 | Kiedy tworzysz klasę lub funkcję, powinieneś napisać test jednostkowy pokrywający i testujący zachowanie, które powinna 22 | posiadać. Najprostszym przykładem jest stworzenie testu, który sprawdzi, czy dla poprawnych danych wejściowych 23 | funkcja/metoda działa prawidłowo, a dla złych - odpowiednio to obsługuje. Dzięki temu wykonując kolejne zmiany i 24 | refaktoryzacje masz pewność, że kod wciąż działa tak jak powinien. 25 | 26 | Testy jednostkowe znajdują zastosowanie również w open-source - dzięki nim możesz w łatwy sposób pokazać, że dana 27 | funkcjonalność nie działa prawidłowo, a następnie po wprowadzeniu poprawki sprawdzić, że ona faktycznie działa. Jeżeli 28 | prowadzisz projekt, w którym korzystasz z tzw. "pull requests", zdecydowanie powinieneś wymagać wykonania odpowiednich 29 | testów jednostkowych. 30 | 31 | [PHPUnit](http://phpunit.de) jest najbardziej znanym frameworkiem, dzięki którym łatwo rozpoczniesz korzystanie z 32 | testów jednostkowych. Są również alternatywy: 33 | 34 | * [SimpleTest](http://simpletest.org) 35 | * [Enhance PHP](http://www.enhance-php.com/) 36 | * [PUnit](http://punit.smf.me.uk/) 37 | 38 | ### Testy integracyjne 39 | 40 | Cytując [Wikipedię](http://en.wikipedia.org/wiki/Integration_testing) (polskie tłumaczenie): 41 | 42 | > Testowanie integracyjne, zwane także Integracją i Testowaniem (ang. Integration and Testing, "I&T") jest fazą produkcji oprogramowania polegającą na automatycznym testowaniu odpowiednich grup modułów jako całość. Testy integracyjne wykonuje się zwykle po wykonaniu odpowiednich testów jednostkowych, a przed testami funkcjonalnymi. Testowanie integracyjne odbywa się na modułach, które zostały przetestowane jednostkowo. Moduły grupuje się w większe zbiory, na których stosuje się odpowiednie testy ujęte w planie testu integracyjnego i dostarcza się zintegrowany produkt, gotowy do testowania funkcjonalnego. 43 | 44 | Proces wykonywania testów integracyjnych rządzi się zasadami podobnymi do testowania jednostkowego, więc do ich 45 | wykonywania możesz używać tych samych narzędzi. 46 | 47 | ### Testy funkcjonalne 48 | 49 | Czasami znane również jako testy akceptacyjne. W odróżnieniu od testów jednostkowych, zamiast konkretnych fragmentów 50 | kodu, testują one pełną aplikację. Takie testy zwykle korzystają z rzeczywistych danych i symulują zachowanie 51 | prawdziwych użytkowników. 52 | 53 | #### Narzędzia do testów funkcjonalnych 54 | 55 | * [Selenium](http://seleniumhq.com) 56 | * [Mink](http://mink.behat.org) 57 | * [Codeception](http://codeception.com) framework do testowania zawierający narzędzia do testów akceptacyjnych 58 | -------------------------------------------------------------------------------- /_posts/08-03-01-Behavior-Driven-Development.md: -------------------------------------------------------------------------------- 1 | --- 2 | isChild: true 3 | --- 4 | 5 | ## Behavior Driven Development {#behavior_driven_development_title} 6 | 7 | Istnieją dwa rodzaje BDD (Behavior-Driven Development): SpecBDD i StoryBDD. Pierwszy z nich charakteryzuje się 8 | technicznym podejściem, gdzie istotny jest kod i jego zachowanie, podczas gdy drugi reprezentuje podejście biznesowe, 9 | gdzie najważniejszą kwestią jest to jak produkt będzie funkcjonował z perspektywy klienta. W PHP dostępne są frameworki 10 | wspierające oba te typy. 11 | 12 | W StoryBDD piszesz zrozumiałe dla człowieka historyjki, które opisują zachowanie Twojej aplikacji. Są one później 13 | uruchamiane jako testy aplikacji. Frameworkiem, który wspiera taki typ testowania jest [Behat](http://behat.org/), 14 | inspirowany projektem [Cucumber](http://cukes.info/) dla Ruby'ego. Do opisywania historyjek w Behat używa się języka 15 | Gherkin DSL (Gherkin Domain Specific Language). 16 | 17 | W SpecBDD piszesz natomiast specyfikacje opisujące w jaki sposób powinien zachowywać się Twój kod. Zamiast testować 18 | funkcję, czy metodę, opisujesz jak powinna się zachowywać. Ten typ BDD wspierany jest przez framework PHPSpec, który 19 | z kolei inspirowany jest projektem [RSpec project](http://rspec.info/), także dla Ruby'ego. 20 | 21 | ### Linki 22 | 23 | * [Behat](http://behat.org/) 24 | * [PHPSpec](http://www.phpspec.net/) 25 | * [Codeception](http://www.codeception.com) framework do testowania aplikacji korzystający z zasad BDD 26 | -------------------------------------------------------------------------------- /_posts/08-04-01-Complementary-Testing-Tools.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Dodatkowe narzędzia 3 | isChild: true 4 | --- 5 | 6 | ## Dodatkowe narzędzia {#complementary_testing_tools_title} 7 | 8 | Oprócz frameworków wspomagających testowanie istnieje również wiele innych narzędzi i bibliotek przydatnych podczas 9 | testowania aplikacji. 10 | 11 | ### Linki 12 | 13 | * [Selenium](http://seleniumhq.org/) narzędzie do automatyzacji testów w przeglądarkach, które może być zintegrowany z [PHPUnit](http://www.phpunit.de/manual/3.1/en/selenium.html) 14 | * [Mockery](https://github.com/padraic/mockery) framework typu Mock Object, który może być zintegrowany z [PHPUnit](http://phpunit.de/) lub [PHPSpec](http://www.phpspec.net/) 15 | -------------------------------------------------------------------------------- /_posts/09-01-01-Servers-and-Deployment.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Serwery i deployment 3 | --- 4 | 5 | # Serwery i deployment {#servers_and_deployment_title} 6 | 7 | Aplikacje napisane w PHP mogą być deployowane na serwery produkcyjne na wiele różnych sposobów. 8 | -------------------------------------------------------------------------------- /_posts/09-02-01-Platform-as-a-Service.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Chmura 3 | isChild: true 4 | --- 5 | 6 | ## Chmura {#platform_as_a_service_title} 7 | 8 | Chmura, czyli PaaS (skrót od Platform as a Service), dostarcza pełną architekturę, której wymaga Twoja aplikacja PHP, 9 | aby być dostępna w Sieci. Oznacza to, że za pomocą kilku kliknięć jesteś w stanie uruchomić takie środowisko, a nawet 10 | zainstalować odpowiednie frameworki, czy biblioteki. 11 | 12 | Ostatnimi czasy, głównie ze względu na łatwość skalowania aplikacji, rozwiązania oparte o chmurę zdobywają coraz 13 | większą popularność. [Listę dostawców](#paas_providers) rozwiązań PaaS znajdziesz w rozdziale [linki](#resources_title); 14 | -------------------------------------------------------------------------------- /_posts/09-03-01-Virtual-or-Dedicated-Servers.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Serwery wirtualne lub dedykowane 3 | isChild: true 4 | --- 5 | 6 | ## Serwery wirtualne lub dedykowane {#virtual_or_dedicated_servers_title} 7 | 8 | Jeżeli potrafisz administrować serwerem bądź planujesz naukę w tym kierunku, zainteresuj się serwerami wirtualnymi. 9 | Dzięki nim masz możliwość skonfigurowania każdego detalu swojego środowiska produkcyjnego. 10 | 11 | ### nginx i PHP-FPM 12 | 13 | PHP potrafi dobrze współdziałać z serwerem [nginx](http://nginx.org) przy użyciu wbudowanego managera procesów FastCGI 14 | (FPM). Nginx jest lekkim i szybkim serwerem WWW, który zużywa znacznie mniej zasobów maszyny niż Apache, przez co 15 | potrafi obsłużyć więcej jednoczesnych procesów. 16 | 17 | * [Czytaj dalej o serwerze nginx](http://nginx.org) 18 | * [Czytaj dalej o PHP-FPM](http://php.net/manual/en/install.fpm.php) 19 | * [Jak bezpiecznie skonfigurować PHP i nginx](https://nealpoole.com/blog/2011/04/setting-up-php-fastcgi-and-nginx-dont-trust-the-tutorials-check-your-configuration/) 20 | 21 | ### Apache i PHP 22 | 23 | PHP i Apache mają za sobą długą historię. Serwer ten cechuje się łatwą, a zarazem dość obszerną konfiguracją, a także 24 | posiada wiele [modułów](http://httpd.apache.org/docs/2.4/mod/) rozszerzających jego możliwości. Na serwerach 25 | hostingowych jest często wybierany jako platforma pod popularne aplikacje open-source (np. Wordpress), czy aplikacje 26 | bazujące na frameworkach. Apache jednakowoż podczas pracy zużywa więcej zasobów serwera, przez co nie może obsłużyć tak 27 | wielu jednoczesnych połączeń, jak jego konkurent, nginx. 28 | 29 | Istnieje kilka możliwości zainstalowania PHP na serwerze Apache. Najczęstszym wyborem jest 30 | [prefork MPM](http://httpd.apache.org/docs/2.4/mod/prefork.html) (od Multi-Processing Modules) i moduł mod_php5. Jest 31 | to najszybszy sposób, który wymaga relatywnie niewielkiego nakładu pracy administracyjnej i jest najlepszym podejściem 32 | dla osób, które wolą ten czas przeznaczyć na kodowanie. Minusem jest fakt, że mod_php5 zużywa więcej zasobów, co może 33 | wpłynąć na szybkość działania. 34 | 35 | Jeżeli chcesz wycisnąć z Apache'a nieco więcej szybkości oraz stabilności działania, możesz użyć tego samego systemu 36 | FPM, który współdziała z serwerem nginx i uruchomić mpm_worker (http://httpd.apache.org/docs/2.4/mod/worker.html) 37 | lub [mpm_event](http://httpd.apache.org/docs/2.4/mod/event.html) z mod_fastcgi lub mod_fcgid. Aplikacje uruchomione w 38 | takiej konfiguracji będą działać szybciej, ale jej instalacja będzie wymagała większego nakładu pracy. 39 | 40 | * [Czytaj o serwerze Apache](http://httpd.apache.org/) 41 | * [Czytaj o Multi-Processing Modules](http://httpd.apache.org/docs/2.4/mod/mpm_common.html) 42 | * [Czytaj o mod_fastcgi](http://www.fastcgi.com/mod_fastcgi/docs/mod_fastcgi.html) 43 | * [Czytaj o mod_fcgid](http://httpd.apache.org/mod_fcgid/) 44 | -------------------------------------------------------------------------------- /_posts/09-04-01-Shared-Servers.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Serwery hostingowe 3 | isChild: true 4 | --- 5 | 6 | ## Serwery hostingowe {#shared_servers_title} 7 | 8 | PHP dzięki swojej popularności jest szeroko wspierany na serwerach hostingowych na całym świecie. Mówiąc szczerze, 9 | trudno w dzisiejszych czasach znaleźć ofertę bez wsparcia dla tego języka. Liczbę ofert godnych zainteresowania 10 | zmniejszy na pewno ważne kryterium - numer zainstalowanej wersji interpretera; ważne, aby była to jedna z ostatnich 11 | wersji. 12 | 13 | Serwery hostingowe to rozwiązania współdzielone, co oznacza, że na jednej fizycznej maszynie może działać wiele 14 | aplikacji. Plusem takiego podejścia jest fakt, że hosting jest relatywnie tani. Minusem jest brak niezależności: 15 | zasoby serwera mogą być zajęte przez innych użytkowników, unieruchamiając bądź ograniczając dostęp do Twojej aplikacji. 16 | Inną istotną sprawą jest fakt, że inne aplikacje zainstalowane na tym samym serwerze mogą posiadać luki bezpieczeństwa, 17 | które pozwolą atakującemu uzyskać dostęp do maszyny i wykonać atak na wszystkich, nawet bezpiecznych aplikacjach. 18 | Jeżeli Twój budżet na to pozwala, powinieneś unikać serwerów hostingowych. 19 | -------------------------------------------------------------------------------- /_posts/10-01-01-Caching.md: -------------------------------------------------------------------------------- 1 | # Caching {#caching_title} 2 | 3 | PHP sam w sobie całkiem dobrze radzi sobie z wydajnością, lecz jeżeli wykonujesz operacje kosztowne czasowo (np. 4 | komunikujesz się ze zdalnymi serwerami, czy ładujesz do pamięci duże pliki), może okazać się, że te miejsca negatywnie 5 | wpływają na wydajność Twojej aplikacji. Na szczęście istnieje kilka narzędzi, które pozwalają na pozbycie się takich 6 | wąskich gardeł, lub ograniczają ilość czasu potrzebnego na ich wykonanie. 7 | -------------------------------------------------------------------------------- /_posts/10-02-01-Bytecode-Cache.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Kod bajtowy 3 | isChild: true 4 | --- 5 | 6 | ## Kod bajtowy {#bytecode_cache_title} 7 | 8 | Kiedy wykonujemy program napisany w PHP, jego kod źródłowy jest najpierw kompilowany do postaci kodu bajtowego, a 9 | następnie uruchamiany. Jeżeli między kolejnymi uruchomieniami plik z kodem nie zostaje zmodyfikowany, wynikowy kod 10 | bajtowy jest taki sam za każdym razem. Oznacza to, że kolejne jego kompilacje nie są potrzebne i powodują jedynie 11 | niepotrzebnym obciążenie procesora. 12 | 13 | Istnieją narzędzia za pomocą których możemy ograniczyć ilość kompilacji zapamiętując wynikowy kod bajtowy, aby kolejne 14 | żądania jego wykonania odbywały się znacznie szybciej. Narzędzia te potrafią drastycznie przyspieszyć działanie 15 | aplikacji, a do tego są bardzo proste w konfiguracji. 16 | 17 | Najbardziej znanymi narzędziami tego typu są: 18 | 19 | * [APC](http://php.net/manual/pl/book.apc.php) 20 | * [XCache](http://xcache.lighttpd.net/) 21 | * [Zend Optimizer+](http://www.zend.com/products/server/) (część pakietu Zend Server) 22 | * [WinCache](http://www.iis.net/download/wincacheforphp) (rozszerzenie MS Windows Server) 23 | -------------------------------------------------------------------------------- /_posts/10-03-01-Object-Caching.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Caching obiektów 3 | isChild: true 4 | --- 5 | 6 | ## Caching obiektów {#object_caching_title} 7 | 8 | Aby przyspieszyć działanie konkretnych funkcjonalności Twojej aplikacji, warto zastanowić się gdzie w kodzie następuje 9 | odwołanie do źródeł danych, których pobranie jest czasochłonne, a częstość zmian jest niska. W takich sytuacjach warto 10 | rozważyć możliwość użycia cachingu tychże danych. Caching polega na zapamiętaniu rezultatu działania określonego 11 | fragmentu kodu w taki sposób, aby później można było wielokrotnie odwołać się do niego, zamiast ponownie wykonywać 12 | czasochłonną operację. Dzięki odpowiedniemu użyciu cache'a programista może w łatwy sposób zwiększyć szybkość działania 13 | aplikacji, a także zminimalizować obciążenie serwera. 14 | 15 | Większość narzędzi, o których pisałem w poprzednim paragrafie, ma funkcję cachingu obiektów. APC, XCache, czy WinCache 16 | oferują proste API do zapamiętywania wyników działania określonego kodu w ich wewnętrznej pamięci. 17 | 18 | Najbardziej znanymi narzędziami do cache'owania danych w PHP jest APC i memcached. Oba oferują proste API i są łatwe w 19 | instalacji i użyciu. Istotną różnicą między nimi jest fakt, że APC, zgodnie ze swoją architekturą, znajduje się na tym 20 | samym serwerze, co kod, który jest uruchamiany, a memcached jest narzędziem sieciowym, które umożliwia dostęp z wielu 21 | różnych maszyn, co powoduje, że jest nieznacznie wolniejszy niż APC. 22 | 23 | Wybór jest dosyć prosty: jeżeli zależy Ci na skalowaniu aplikacji, wybierz zorientowany na to memcached. Jeżeli Twoja 24 | aplikacja będzie działać na jednym serwerze, użyj APC. 25 | 26 | Przykładowy kod wykorzystujący APC: 27 | 28 | {% highlight php %} 29 | PHP: The Right Way. Po polsku.

14 | 15 | 16 | PHP: The Right Way. Po polsku. 17 | 18 | 19 | ## Button 2 (120x60) 20 | 21 |

PHP: The Right Way. Po polsku.

22 | 23 | 24 | PHP: The Right Way. Po polsku. 25 | 26 | 27 | ## Leaderboard (728x90) 28 | 29 |

PHP: The Right Way. Po polsku.

30 | 31 | 32 | PHP: The Right Way. Po polsku. 33 | 34 | 35 | ## Large Rectangle (386x280) 36 | 37 |

PHP: The Right Way. Po polsku.

38 | 39 | 40 | PHP: The Right Way. Po polsku. 41 | 42 | 43 | ## Medium Rectangle (300x250) 44 | 45 |

PHP: The Right Way. Po polsku.

46 | 47 | 48 | PHP: The Right Way. Po polsku. 49 | 50 | 51 | ## Rectangle (180x150) 52 | 53 |

PHP: The Right Way. Po polsku.

54 | 55 | 56 | PHP: The Right Way. Po polsku. 57 | 58 | 59 | ## Square Button (125x125) 60 | 61 |

PHP: The Right Way. Po polsku.

62 | 63 | 64 | PHP: The Right Way. Po polsku. 65 | 66 | 67 | ## Vertical Rectangle (240x400) 68 | 69 |

PHP: The Right Way. Po polsku.

70 | 71 | 72 | PHP: The Right Way. Po polsku. 73 | 74 | -------------------------------------------------------------------------------- /images/banners/btn1-120x90.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartosz-maciaszek/php-the-right-way/dcf7c3078f8dc42054e220031c4bb13f4153a9b3/images/banners/btn1-120x90.png -------------------------------------------------------------------------------- /images/banners/btn2-120x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartosz-maciaszek/php-the-right-way/dcf7c3078f8dc42054e220031c4bb13f4153a9b3/images/banners/btn2-120x60.png -------------------------------------------------------------------------------- /images/banners/leaderboard-728x90.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartosz-maciaszek/php-the-right-way/dcf7c3078f8dc42054e220031c4bb13f4153a9b3/images/banners/leaderboard-728x90.png -------------------------------------------------------------------------------- /images/banners/lg-rect-386x280.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartosz-maciaszek/php-the-right-way/dcf7c3078f8dc42054e220031c4bb13f4153a9b3/images/banners/lg-rect-386x280.png -------------------------------------------------------------------------------- /images/banners/med-rect-300x250.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartosz-maciaszek/php-the-right-way/dcf7c3078f8dc42054e220031c4bb13f4153a9b3/images/banners/med-rect-300x250.png -------------------------------------------------------------------------------- /images/banners/rect-180x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartosz-maciaszek/php-the-right-way/dcf7c3078f8dc42054e220031c4bb13f4153a9b3/images/banners/rect-180x150.png -------------------------------------------------------------------------------- /images/banners/sq-btn-125x125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartosz-maciaszek/php-the-right-way/dcf7c3078f8dc42054e220031c4bb13f4153a9b3/images/banners/sq-btn-125x125.png -------------------------------------------------------------------------------- /images/banners/vert-rect-240x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartosz-maciaszek/php-the-right-way/dcf7c3078f8dc42054e220031c4bb13f4153a9b3/images/banners/vert-rect-240x400.png -------------------------------------------------------------------------------- /images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartosz-maciaszek/php-the-right-way/dcf7c3078f8dc42054e220031c4bb13f4153a9b3/images/favicon.png -------------------------------------------------------------------------------- /images/nmc-logo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartosz-maciaszek/php-the-right-way/dcf7c3078f8dc42054e220031c4bb13f4153a9b3/images/nmc-logo.gif -------------------------------------------------------------------------------- /images/og-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartosz-maciaszek/php-the-right-way/dcf7c3078f8dc42054e220031c4bb13f4153a9b3/images/og-logo.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | description: "Przystępny zbiór najlepszych praktyk, standardów kodowania oraz linków do sprawdzonych tutoriali dostępnych w Sieci na temat PHP. Po polsku." 4 | --- 5 | 6 | {% capture welcome_content %}{% include welcome.md %}{% endcapture %} 7 | {{ welcome_content|markdownify }} 8 | 9 | {% capture backtotop %}[Na górę](#top){.top}{% endcapture %} 10 | {% for post in site.posts reversed %} 11 | {% if post.isChild != true and loop.first != true %} 12 | {{ backtotop|markdownify }} 13 | {% endif %} 14 |
15 | {{ post.content }} 16 |
17 | {% endfor %} 18 | {{ backtotop|markdownify }} 19 | -------------------------------------------------------------------------------- /pages/Design-Patterns.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Design Patterns 4 | --- 5 | 6 | # Design Patterns 7 | 8 | There are numerous ways to structure the code and project for you web application, and you can put as much or as little 9 | thought as you like into architecting. But it is usually a good idea to follow to common patterns because it will make 10 | your code easier to manage and easier for others to understand. 11 | 12 | * [Architectural pattern on Wikipedia](https://en.wikipedia.org/wiki/Architectural_pattern) 13 | * [Software design pattern on Wikipedia](https://en.wikipedia.org/wiki/Software_design_pattern) 14 | 15 | ## Factory 16 | 17 | One of the most commonly used design patterns is the factory pattern. In this pattern, a class simply creates 18 | the object you want to use. Consider the following example of the factory pattern: 19 | 20 | {% highlight php %} 21 | vehicle_make = $make; 30 | $this->vehicle_model = $model; 31 | } 32 | 33 | public function get_make_and_model() 34 | { 35 | return $this->vehicle_make . ' ' . $this->vehicle_model; 36 | } 37 | } 38 | 39 | class AutomobileFactory 40 | { 41 | public static function create($make, $model) 42 | { 43 | return new Automobile($make, $model); 44 | } 45 | } 46 | 47 | // have the factory create the Automobile object 48 | $veyron = AutomobileFactory::create('Bugatti', 'Veyron'); 49 | 50 | print_r($veyron->get_make_and_model()); // outputs "Bugatti Veyron" 51 | {% endhighlight %} 52 | 53 | This code uses a factory to create the Automobile object. There are two possible benefits to building your code this 54 | way, the first is that if you need to change, rename, or replace the Automobile class later on you can do so and you 55 | will only have to modify the code in the factory, instead of every place in your project that uses the Automobile 56 | class. The second possible benefit is that if creating the object is a complicated job you can do all of the work in 57 | the factory, instead of repeating it every time you want to create a new instance. 58 | 59 | Using the factory pattern isn't always necessary (or wise). The example code used here is so simple that a factory 60 | would simply be adding unneeded complexity. However if you are making a fairly large or complex project you may save 61 | yourself a lot of trouble down the road by using factories. 62 | 63 | * [Factory pattern on Wikipedia](https://en.wikipedia.org/wiki/Factory_pattern) 64 | 65 | ## Front Controller 66 | 67 | The front controller pattern is where you have a single entrance point for you web application (e.g. index.php) that 68 | handles all of the requests. This code is responsible for loading all of the dependencies, processing the request and 69 | sending the response to the browser. The front controller pattern can be beneficial because it encourages modular code 70 | and gives you a central place to hook in code that should be run for every request (such as input sanitization). 71 | 72 | * [Front Controller pattern on Wikipedia](https://en.wikipedia.org/wiki/Front_Controller_pattern) 73 | 74 | ## Model-View-Controller 75 | 76 | The model-view-controller (MVC) pattern and its relatives HMVC and MVVM let you break up code into logical objects that 77 | serve very specific purposes. Models serve as a data access layer where data it fetched and returned in formats usable 78 | throughout your application. Controllers handle the request, process the data returned from models and load views to 79 | send in the response. And views are display templates (markup, xml, etc) that are sent in the response to the web 80 | browser. 81 | 82 | MVC is the most common architectural pattern used in the popular [PHP frameworks](https://github.com/codeguy/php-the-right-way/wiki/Frameworks). 83 | 84 | Learn more about MVC and its relatives: 85 | 86 | * [MVC](https://en.wikipedia.org/wiki/Model%E2%80%93View%E2%80%93Controller) 87 | * [HMVC](https://en.wikipedia.org/wiki/Hierarchical_model%E2%80%93view%E2%80%93controller) 88 | * [MVVM](https://en.wikipedia.org/wiki/Model_View_ViewModel) 89 | -------------------------------------------------------------------------------- /pages/Functional-Programming.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Functional Programming in PHP 4 | --- 5 | 6 | # Functional Programming in PHP 7 | 8 | PHP supports first-class function, meaning that a function can be assigned to a variable. Both user defined and built-in 9 | functions can be referenced by a variable and invoked dynamically. Functions can be passed as arguments to other 10 | functions (feature called Higher-order functions) and function can return other functions. 11 | 12 | Recursion, a feature that allows a function to call itself is supported by the language, but most of the PHP code focus 13 | on iteration. 14 | 15 | New anonymous functions (with support for closures) are present since PHP 5.3 (2009). 16 | 17 | PHP 5.4 added the ability to bind closures to an object's scope and also improved support for callables such that they 18 | can be used interchangeably with anonymous functions in almost all cases. 19 | 20 | The most common usage of higher-order functions is when implementing a strategy pattern. Built-in `array_filter` 21 | function asks both for the input array (data) and a function (a strategy or a callback) used as a filter function on 22 | each array item. 23 | 24 | {% highlight php %} 25 | $min 55 | * 56 | * Returns a single filter out of a family of "greater than n" filters 57 | */ 58 | function criteria_greater_than($min) 59 | { 60 | return function($item) use ($min) { 61 | return $item > $min; 62 | }; 63 | } 64 | 65 | $input = array(1, 2, 3, 4, 5, 6); 66 | 67 | // Use array_filter on a input with a selected filter function 68 | $output = array_filter($input, criteria_greater_than(3)); 69 | 70 | print_r($output); // items > 3 71 | {% endhighlight %} 72 | 73 | Each filter function in the family accepts only elements greater than some minimum value. Single filter returned by 74 | `criteria_greater_than` is a closure whith `$min` argument closed by the value in the scope (given as an argument when 75 | `criteria_greater_than` is called). 76 | 77 | Early binding is used by default for importing `$min` variable into the created function. For true closures with late 78 | binding one should use a reference when importing. Imagine a templating or input validation libraries, where closure is 79 | defined to capture variables in scope and access them later when the anonymous function is evaluated. 80 | 81 | * [Read about Anonymous functions][anonymous-functions] 82 | * [More details in the Closures RFC][closures-rfc] 83 | * [Read about dynamically invoking functions with `call_user_func_array`][call-user-func-array] 84 | 85 | [anonymous-functions]: http://www.php.net/manual/en/functions.anonymous.php 86 | [call-user-func-array]: http://php.net/manual/en/function.call-user-func-array.php 87 | [closures-rfc]: https://wiki.php.net/rfc/closures 88 | -------------------------------------------------------------------------------- /pages/example.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: Przykładowa strona 4 | --- 5 | 6 | # Tytuł strony 7 | 8 | Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod 9 | tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, 10 | quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo 11 | consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse 12 | cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non 13 | proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 14 | 15 | Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod 16 | tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, 17 | quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo 18 | consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse 19 | cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non 20 | proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 21 | 22 | Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod 23 | tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, 24 | quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo 25 | consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse 26 | cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non 27 | proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 28 | -------------------------------------------------------------------------------- /scripts/setup.js: -------------------------------------------------------------------------------- 1 | (function ($) { 2 | // Load contributors 3 | var $contributors = $('#contributors'); 4 | if ( $contributors.length ) { 5 | var fail = function () { 6 | $contributors.html('

This project would not be possible without the help of our amazing contributors on GitHub.

'); 7 | }; 8 | $.ajax({ 9 | cache: false, 10 | dataType: 'jsonp', 11 | timeout: 3000, 12 | type: 'GET', 13 | url: 'https://api.github.com/repos/codeguy/php-the-right-way/contributors' 14 | }).done(function (data) { 15 | if ( data.data && data.data.length ) { 16 | var $ul = $(''), dataLength = data.data.length; 17 | for ( var i = 0; i < dataLength; i++ ) { 18 | $ul.append(['
  • ', data.data[i].login, '
  • '].join('')); 19 | } 20 | $contributors.html($ul); 21 | } else { 22 | fail(); 23 | } 24 | }).fail(fail); 25 | } 26 | })(jQuery); 27 | 28 | (function ($) { 29 | //Add current view's highlighting to the navigation 30 | 31 | /** helper for highlighting */ 32 | function highlightNav(navLinks,id) 33 | { 34 | navLinks.filter('[href="/#'+id+'"]').addClass("active"); 35 | } 36 | 37 | $(window).scroll(function() { 38 | //console.log("They see me scrollin, they hatin"); 39 | 40 | //clear highlighting 41 | var navLinks = $('.site-navigation a'); 42 | navLinks.removeClass("active"); 43 | 44 | //calc current viewport 45 | var viewTop = $(window).scrollTop(); 46 | var viewBottom = viewTop + $(window).height(); 47 | 48 | //for all h1 and h2 elements, check if they are visible 49 | //performance tweak: stop each() after the first element is found to be behind view 50 | var previous = ""; 51 | var foundOne = false; 52 | var fallback = ""; 53 | $('h1, h2').each(function(i,e) { 54 | //get element position; 55 | var eTop = $(e).offset().top; 56 | var eBottom = eTop + $(e).height(); 57 | var id=e.id; 58 | 59 | if (eTop >= viewTop) { 60 | //if we are passed the view and no heading was highlighted yet, store previous one as fallback 61 | if (! foundOne) { 62 | fallback=previous; 63 | } 64 | if (eBottom <= viewBottom) { 65 | highlightNav(navLinks, id); 66 | foundOne = true; 67 | } else { 68 | return false; //break the each(), the rest is below 69 | } 70 | } 71 | previous=id; 72 | }); 73 | //no h1/h2 is in the viewport, so highlight the last one above 74 | if (! foundOne) { 75 | highlightNav(navLinks, fallback); 76 | } 77 | }); 78 | })(jQuery); 79 | 80 | -------------------------------------------------------------------------------- /sitemap.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | http://www.phptherightway.com/index.html 5 | 2012-07-07T01:00:00-05:00 6 | daily 7 | 1 8 | 9 | 10 | http://www.phptherightway.com/banners.html 11 | 2012-07-08T14:11:00-05:00 12 | weekly 13 | 0.5 14 | 15 | 16 | -------------------------------------------------------------------------------- /styles/all.less: -------------------------------------------------------------------------------- 1 | /* ========================================================================== 2 | NMC Bootstrap 3 | 4 | This LESS file imports all other LESS files. You should compile 5 | and minify this file before site launch. 6 | ========================================================================== */ 7 | 8 | /* Import NMC bootstrap */ 9 | 10 | @import "base/all"; 11 | 12 | /* Import site-specific styles */ 13 | 14 | @import "site/site-header.less"; 15 | @import "site/site-navigation.less"; 16 | @import "site/site-content.less"; 17 | @import "site/site-footer.less"; 18 | 19 | /* Tablets and Smartphones */ 20 | 21 | @media only screen and (max-width : 1024px) { 22 | .build-date{ 23 | text-align: center; 24 | } 25 | .site-header{ 26 | height: 220px; 27 | position: absolute; 28 | top: 20px; 29 | left: 0; 30 | width: 100%; 31 | } 32 | .fork-me img{ 33 | height: 110px; 34 | width: 110px; 35 | } 36 | .site-navigation{ 37 | margin-top: 240px; 38 | padding: 20px; 39 | position: relative; 40 | width: auto; 41 | 42 | ul{ 43 | border: 1px solid #999; 44 | border-bottom: none; 45 | } 46 | li{ 47 | .man; 48 | .pan; 49 | } 50 | a{ 51 | background: #CCC; 52 | display: block; 53 | border-bottom: 1px solid #999; 54 | padding: 10px; 55 | text-decoration: none; 56 | } 57 | ul ul{ 58 | border: none; 59 | .man; 60 | .pan; 61 | } 62 | ul ul a{ 63 | background: transparent; 64 | } 65 | } 66 | .site-content{ 67 | padding: 20px; 68 | } 69 | .top{ 70 | display: inline-block; 71 | float: none; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /styles/base/all.less: -------------------------------------------------------------------------------- 1 | @import "reset"; 2 | @import "prefixer"; 3 | @import "spacing"; 4 | @import "typography"; 5 | @import "idioms"; 6 | @import "grid"; 7 | @import "bars-buttons"; 8 | @import "buttons"; -------------------------------------------------------------------------------- /styles/base/bars-buttons.less: -------------------------------------------------------------------------------- 1 | .button() { 2 | .border-box; 3 | cursor: pointer; 4 | display: inline-block; 5 | .phh; 6 | text-align: center; 7 | font-weight: bold; 8 | } 9 | .button-hover(){ 10 | text-decoration: none; 11 | } 12 | .bar() { 13 | display: block; 14 | .pah; 15 | text-align: center; 16 | font-weight: bold; 17 | } 18 | 19 | /* Sizes */ 20 | 21 | .btn-size(@scale){ 22 | height: @baseline * @scale !important; 23 | padding-bottom: 0 !important; 24 | padding-top: 0 !important; 25 | line-height: @baseline * (@scale * 0.9); 26 | } 27 | .btn-half{ 28 | .btn-size(1); 29 | font-size: 0.8em; 30 | } 31 | .btn-single{ 32 | .btn-size(1.5); 33 | font-size: 1em; 34 | } 35 | .btn-double{ 36 | .btn-size(2); 37 | font-size: 1.1em; 38 | } 39 | 40 | /* Shapes */ 41 | 42 | .bb-shape-square() { 43 | .border-radius(0); 44 | } 45 | .bb-shape-rounded(@rad:3px) { 46 | .border-radius(@rad); 47 | } 48 | .bb-shape-round() { 49 | .border-radius(@baseline); 50 | } 51 | 52 | /* Text */ 53 | 54 | .bb-text-dark(){ 55 | color: #333; 56 | text-shadow: 0 1px 0 #fff; 57 | } 58 | .bb-text-light(){ 59 | color: #fff; 60 | text-shadow: 0 -1px 0 rgba(0,0,0,.3); 61 | } 62 | .bb-text-color(@color){ 63 | 64 | } 65 | 66 | /* Color */ 67 | 68 | .bb-color-plain(@color){ 69 | background: @color; 70 | } 71 | .bb-color-gradient(@color){ 72 | .gradient(@color,lighten(@color,10%),darken(@color,10%)); 73 | } 74 | .bb-color-soft(@color){ 75 | .gradient(@color,lighten(@color,5%),darken(@color,5%)); 76 | } 77 | .bb-color-gloss(@color){ 78 | @topStart: desaturate(lighten(@color,40%),20%); 79 | @topStop: desaturate(lighten(@color,20%),40%); 80 | @bottomStart: desaturate(lighten(@color,10%),30%); 81 | @bottomStop: desaturate(lighten(@color,15%),30%); 82 | .linear-gradient-top(@color,@topStart,0%,@topStop,50%,@bottomStart,50%,@bottomStop,100%); 83 | } 84 | 85 | /* Border */ 86 | 87 | .bb-border-noborder(){ 88 | border: none; 89 | } 90 | .bb-border-plain(@color){ 91 | border: 1px solid darken(@color,10%); 92 | } 93 | .bb-border-contrast(@color){ 94 | border: 1px solid darken(@color,15%); 95 | .box-shadow(inset 0 0 1px 1px lighten(@color,15%)); 96 | } 97 | .bb-border-meta(@color){ 98 | border: 1px solid darken(@color,15%); 99 | .box-shadow(inset 0 2px 1px -1px lighten(@color,20%)); 100 | } 101 | 102 | /* Minimal */ 103 | 104 | .button-minimal(@color) { 105 | .button(); 106 | .bb-shape-rounded(); 107 | .bb-color-plain(@color); 108 | .bb-border-contrast(@color); 109 | .bb-text-dark(); 110 | } 111 | .button-minimal-hover(@color){ 112 | .button-minimal(darken(@color,5%)); 113 | .button-hover(); 114 | } 115 | .button-minimal-active(@color){ 116 | .button-minimal-hover(darken(@color,5%)); 117 | } 118 | .bar-minimal(@color) { 119 | .button-minimal(@color); 120 | .bar(); 121 | } 122 | 123 | /* Clean */ 124 | 125 | .button-clean(@color) { 126 | .button(); 127 | .bb-shape-rounded(); 128 | .bb-color-gradient(@color); 129 | .bb-border-plain(darken(@color,5%)); 130 | .bb-text-dark(); 131 | } 132 | .button-clean-hover(@color){ 133 | .button-clean(darken(@color,5%)); 134 | .button-hover(); 135 | } 136 | .button-clean-active(@color){ 137 | .button-clean-hover(darken(@color,5%)); 138 | } 139 | .bar-clean(@color){ 140 | .button-clean(@color); 141 | .bar(); 142 | } 143 | 144 | /* Soft */ 145 | 146 | .button-soft(@color) { 147 | .button(); 148 | .bb-shape-rounded(); 149 | .bb-color-soft(@color); 150 | .bb-border-meta(darken(@color,5%)); 151 | .bb-text-light(); 152 | } 153 | .button-soft-hover(@color){ 154 | .button-soft(darken(@color,5%)); 155 | .button-hover(); 156 | } 157 | .button-soft-active(@color){ 158 | .button-soft-hover(darken(@color,5%)); 159 | } 160 | .bar-soft(@color){ 161 | .button-soft(@color); 162 | .bar(); 163 | } 164 | 165 | /* Pill */ 166 | 167 | .button-pill(@color) { 168 | .button(); 169 | .bb-shape-round(); 170 | .bb-color-soft(@color); 171 | .bb-border-meta(darken(@color,5%)); 172 | .bb-text-light(); 173 | } 174 | .button-pill-hover(@color){ 175 | .button-pill(darken(@color,5%)); 176 | .button-hover(); 177 | } 178 | .button-pill-active(@color){ 179 | .button-pill-hover(darken(@color,5%)); 180 | } 181 | .bar-pill(@color){ 182 | .button-pill(@color); 183 | .bar(); 184 | } 185 | 186 | /* Gloss */ 187 | 188 | .button-gloss(@color) { 189 | .button(); 190 | .bb-shape-rounded(5px); 191 | .bb-color-gloss(@color); 192 | .bb-border-plain(darken(@color,5%)); 193 | .box-shadow(inset 0 1px 0 0 rgba(255,255,255,.5)); 194 | .bb-text-light(); 195 | } 196 | .button-gloss-hover(@color){ 197 | .button-gloss(darken(@color,5%)); 198 | .box-shadow(inset 0 1px 0 0 rgba(255,255,255,.3)); 199 | .button-hover(); 200 | } 201 | .button-gloss-active(@color){ 202 | .button-gloss-hover(darken(@color,5%)); 203 | .box-shadow(inset 0 0 5px 0 rgba(0,0,0,.3)); 204 | } 205 | .bar-gloss(@color){ 206 | .button-gloss(@color); 207 | .bar(); 208 | } 209 | 210 | @btn-minimal-color: #eee; 211 | .btn-minimal { .button-minimal(@btn-minimal-color); } 212 | .btn-minimal:hover { .button-minimal-hover(@btn-minimal-color); } 213 | .btn-minimal:active { .button-minimal-active(@btn-minimal-color); } 214 | 215 | @btn-clean-color: #eee; 216 | .btn-clean { .button-clean(@btn-clean-color); } 217 | .btn-clean:hover { .button-clean-hover(@btn-clean-color); } 218 | .btn-clean:active { .button-clean-active(@btn-clean-color); } 219 | 220 | @btn-soft-color: #6C84AB; 221 | .btn-soft { .button-soft(@btn-soft-color); } 222 | .btn-soft:hover { .button-soft-hover(@btn-soft-color); } 223 | .btn-soft:active { .button-soft-active(@btn-soft-color); } 224 | 225 | @btn-pill-color: #6C84AB; 226 | .btn-pill { .button-pill(@btn-pill-color); } 227 | .btn-pill:hover { .button-pill-hover(@btn-pill-color); } 228 | .btn-pill:active { .button-pill-active(@btn-pill-color); } 229 | 230 | @btn-gloss-color: #172D6E; 231 | .btn-gloss { .button-gloss(@btn-gloss-color); } 232 | .btn-gloss:hover { .button-gloss-hover(@btn-gloss-color); } 233 | .btn-gloss:active { .button-gloss-active(@btn-gloss-color); } 234 | 235 | 236 | .bar-minimal { .bar-minimal(@btn-minimal-color); } 237 | .bar-clean { .bar-clean(@btn-clean-color); } 238 | .bar-soft { .bar-soft(@btn-soft-color); } 239 | .bar-pill { .bar-pill(@btn-pill-color); } 240 | .bar-gloss { .bar-gloss(@btn-gloss-color); } -------------------------------------------------------------------------------- /styles/base/buttons.less: -------------------------------------------------------------------------------- 1 | /* ========================================================================== 2 | Settings 3 | ========================================================================== */ 4 | 5 | @import 'variables.less'; 6 | 7 | /* 8 | @baseline: @baseline; 9 | @button-color: @button-color; 10 | @button-primary-color: @button-primary-color; 11 | @button-info-color: @button-info-color; 12 | @button-success-color: @button-success-color; 13 | @button-warning-color: @button-warning-color; 14 | @button-danger-color: @button-danger-color; 15 | */ 16 | 17 | /* ========================================================================== 18 | Default 19 | ========================================================================== */ 20 | 21 | .btn{ 22 | .btn-s; 23 | background-clip: border-box !important; 24 | background-repeat: repeat-x; 25 | border: 1px solid rgba(0, 0, 0, 0.25); 26 | .border-box; 27 | .border-radius(4px); 28 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); 29 | cursor: pointer; 30 | display: inline-block; 31 | .gradient(@button-color, lighten(@button-color, 10%), @button-color); 32 | .phh; 33 | .pvn; 34 | .transition(background-position linear 0.1s); 35 | vertical-align: middle; 36 | color: #333; 37 | font-family: @body-font-family; 38 | text-decoration: none !important; 39 | text-shadow: rgba(255,255,255,0.75) 0 1px 0; 40 | 41 | &:hover{ 42 | background-position: 0 -15px; 43 | } 44 | } 45 | 46 | /* ========================================================================== 47 | Styles 48 | ========================================================================== */ 49 | 50 | .btn-primary, 51 | .btn-info, 52 | .btn-success, 53 | .btn-warning, 54 | .btn-danger{ 55 | color: #FFF !important; 56 | text-shadow: rgba(0,0,0,0.25) 0 -1px 0 !important; 57 | } 58 | .btn-primary{ 59 | .btn; 60 | .gradient(@button-primary-color, lighten(@button-primary-color, 10%), @button-primary-color); 61 | } 62 | .btn-info{ 63 | .btn; 64 | .gradient(@button-info-color, lighten(@button-info-color, 10%), @button-info-color); 65 | } 66 | .btn-success{ 67 | .btn; 68 | .gradient(@button-success-color, lighten(@button-success-color, 10%), @button-success-color); 69 | } 70 | .btn-warning{ 71 | .btn; 72 | .gradient(@button-warning-color, lighten(@button-warning-color, 10%), @button-warning-color); 73 | } 74 | .btn-danger{ 75 | .btn; 76 | .gradient(@button-danger-color, lighten(@button-danger-color, 10%), @button-danger-color); 77 | } 78 | 79 | /* ========================================================================== 80 | Sizes (Half = h, Single = s, Double = d) 81 | ========================================================================== */ 82 | 83 | .btn-h, .btn-half{ 84 | height: @baseline; 85 | font-size: @baseline * 0.6; 86 | line-height: @baseline; 87 | } 88 | .btn-s, .btn-single{ 89 | height: @baseline * 1.5; 90 | font-size: @baseline * 0.75; 91 | line-height: @baseline * 1.5; 92 | } 93 | .btn-d, .btn-double{ 94 | height: @baseline * 2; 95 | font-size: @baseline; 96 | line-height: @baseline * 2; 97 | } -------------------------------------------------------------------------------- /styles/base/grid.less: -------------------------------------------------------------------------------- 1 | /** 2 | * Hybrid Grid Sytem 3 | * 4 | * Blend of the Semantic Grid System and Zurb Foundation with a little Twitter Bootstrap 5 | */ 6 | 7 | /* Settings */ 8 | 9 | @import 'variables.less'; 10 | 11 | /* 12 | @fixed-column-width: 40px; 13 | @fixed-gutter-width: 20px; 14 | @fixed-columns: 12; 15 | 16 | @fluid-column-width: 4.3%; 17 | @fluid-gutter-width: 4.4%; 18 | @fluid-columns: 12; 19 | 20 | @mobile-break-width: 480px; 21 | @mobile-column-width: 8.6%; 22 | @mobile-gutter-width: 8.8%; 23 | @mobile-columns: 6; 24 | */ 25 | 26 | /* Grid */ 27 | 28 | #grid { 29 | 30 | .cols(@cols,@width,@gutter){ 31 | .border-box(); 32 | width: ((@cols * @width) + ((@cols - 1) * @gutter)); 33 | margin-left: @gutter; 34 | position: relative; 35 | display: inline; 36 | float: left; 37 | min-height: 1px; 38 | &:first-child { 39 | margin-left: 0; 40 | } 41 | &:last-child { 42 | float: right; 43 | } 44 | } 45 | 46 | } 47 | 48 | .grid-fixed,.grid-fluid { 49 | .clearfix; 50 | .row { 51 | .border-box(); 52 | display: block; 53 | width: 100%; 54 | margin: 0 auto; 55 | .clearfix; 56 | 57 | .center,.center:last-child { 58 | float: none; 59 | display: block; 60 | margin: 0 auto; 61 | } 62 | } 63 | } 64 | 65 | .grid-fixed { 66 | @total-width: (@fixed-column-width*@fixed-columns) + (@fixed-gutter-width*(@fixed-columns - 1)); 67 | @column-width: @fixed-column-width; 68 | @gutter-width: @fixed-gutter-width; 69 | @columns: @fixed-columns; 70 | width: @total-width; 71 | 72 | /* This is duplicated in both classes. Unavoidable. */ 73 | .colX (@index) when (@index > 0) { 74 | (~".col@{index}") { 75 | #grid > .cols(@index,@column-width,@gutter-width); 76 | } 77 | .colX(@index - 1); 78 | } 79 | .colX (0) {} 80 | .colX(@columns); 81 | 82 | .offsetX (@index) when (@index > 0) { 83 | (~".offset@{index}") { 84 | margin-left: (@index * @column-width) + ((@index + 1) * @gutter-width); 85 | } 86 | .offsetX(@index - 1); 87 | } 88 | .offsetX (0) {} 89 | .offsetX(@columns - 1); 90 | 91 | .pushX (@index) when (@index > 0) { 92 | (~".push@{index}") { 93 | left: @index * (@column-width + @gutter-width); 94 | } 95 | .pushX(@index - 1); 96 | } 97 | .pushX (0) {} 98 | .pushX(@columns - 1); 99 | 100 | .pullX (@index) when (@index > 0) { 101 | (~".pull@{index}") { 102 | right: @index * (@column-width + @gutter-width); 103 | } 104 | .pullX(@index - 1); 105 | } 106 | .pullX (0) {} 107 | .pullX(@columns - 1); 108 | } 109 | 110 | 111 | .grid-fluid { 112 | @total-width: 100%; 113 | @column-width: @fluid-column-width; 114 | @gutter-width: @fluid-gutter-width; 115 | @columns: @fluid-columns; 116 | width: @total-width; 117 | 118 | /* This is duplicated in both classes. Unavoidable. */ 119 | .colX (@index) when (@index > 0) { 120 | (~".col@{index}") { 121 | #grid > .cols(@index,@column-width,@gutter-width); 122 | } 123 | .colX(@index - 1); 124 | } 125 | .colX (0) {} 126 | .colX(@columns); 127 | 128 | .offsetX (@index) when (@index > 0) { 129 | (~".offset@{index}") { 130 | margin-left: (@index * @column-width) + ((@index + 1) * @gutter-width); 131 | } 132 | .offsetX(@index - 1); 133 | } 134 | .offsetX (0) {} 135 | .offsetX(@columns - 1); 136 | 137 | .pushX (@index) when (@index > 0) { 138 | (~".push@{index}") { 139 | left: @index * (@column-width + @gutter-width); 140 | } 141 | .pushX(@index - 1); 142 | } 143 | .pushX (0) {} 144 | .pushX(@columns - 1); 145 | 146 | .pullX (@index) when (@index > 0) { 147 | (~".pull@{index}") { 148 | right: @index * (@column-width + @gutter-width); 149 | } 150 | .pullX(@index - 1); 151 | } 152 | .pullX (0) {} 153 | .pullX(@columns - 1); 154 | } 155 | 156 | 157 | @media all and (max-width: @mobile-break-width) { 158 | 159 | // Reset all columns to full width 160 | .grid-fixed { 161 | .colX (@index) when (@index > 0) { 162 | (~".col@{index}") { 163 | width: 100%; 164 | margin: 0; 165 | left: 0; 166 | right: 0; 167 | } 168 | .colX(@index - 1); 169 | } 170 | .colX (0) {} 171 | .colX(@fixed-columns); 172 | } 173 | .grid-fluid { 174 | .colX (@index) when (@index > 0) { 175 | (~".col@{index}") { 176 | width: 100%; 177 | margin: 0; 178 | left: 0; 179 | right: 0; 180 | } 181 | .colX(@index - 1); 182 | } 183 | .colX (0) {} 184 | .colX(@fluid-columns); 185 | } 186 | 187 | .grid-fixed, .grid-fluid { 188 | @total-width: 100%; 189 | @column-width: @mobile-column-width; 190 | @gutter-width: @mobile-gutter-width; 191 | @columns: @mobile-columns; 192 | width: @total-width; 193 | 194 | .m-colX (@index) when (@index > 0) { 195 | (~".m-col@{index}") { 196 | #grid > .cols(@index,@column-width,@gutter-width); 197 | } 198 | .m-colX(@index - 1); 199 | } 200 | .m-colX (0) {} 201 | .m-colX(@mobile-columns); 202 | 203 | .m-offsetX (@index) when (@index > 0) { 204 | (~".m-offset@{index}") { 205 | margin-left: (@index * @column-width) + ((@index + 1) * @gutter-width); 206 | } 207 | .m-offsetX(@index - 1); 208 | } 209 | .m-offsetX (0) {} 210 | .m-offsetX(@columns - 1); 211 | 212 | .m-pushX (@index) when (@index > 0) { 213 | (~".m-push@{index}") { 214 | left: @index * (@column-width + @gutter-width); 215 | } 216 | .m-pushX(@index - 1); 217 | } 218 | .m-pushX (0) {} 219 | .m-pushX(@columns - 1); 220 | 221 | .m-pullX (@index) when (@index > 0) { 222 | (~".m-pull@{index}") { 223 | right: @index * (@column-width + @gutter-width); 224 | } 225 | .m-pullX(@index - 1); 226 | } 227 | .m-pullX (0) {} 228 | .m-pullX(@columns - 1); 229 | } 230 | 231 | } 232 | -------------------------------------------------------------------------------- /styles/base/idioms.less: -------------------------------------------------------------------------------- 1 | /** 2 | * New Media Campaigns Idioms 3 | * 4 | * These are common patterns we use in all of our 5 | * projects. They are consolidated here to keep code DRY. 6 | * 7 | * Listing 8 | * * .no-text, .text-replace 9 | * * .no-list 10 | * * .no-form 11 | * * .fixed-width(@width) 12 | * * .column-width(@width) 13 | * * .column-left(@width) 14 | * * .column-right(@width) 15 | * * .full-size 16 | * * .absolute-default 17 | * * .absolute-fullsize 18 | * * .clearfix 19 | */ 20 | 21 | /* Hides text when using image replacement */ 22 | .no-text, .text-replace{ 23 | overflow: hidden; 24 | text-indent: 100%; 25 | white-space: nowrap; 26 | } 27 | 28 | /* Removes bullets, margin, and padding from list */ 29 | .no-list{ 30 | list-style: none; 31 | margin: 0; 32 | padding: 0; 33 | } 34 | 35 | /* Removes webkit styling from form element */ 36 | .no-form{ 37 | border: none; 38 | margin: 0; 39 | padding: 0; 40 | -webkit-appearance: none; 41 | } 42 | 43 | /* Center a fixed width container */ 44 | .fixed-width(@width) { 45 | margin: 0 auto; 46 | width: @width; 47 | } 48 | 49 | /* Adds left or right columns (e.g. content and sidebar) */ 50 | .column-width(@width){ 51 | display: inline; 52 | width: @width; 53 | } 54 | .column-left(@width){ 55 | .column-width(@width); 56 | float: left; 57 | } 58 | .column-right(@width){ 59 | .column-width(@width); 60 | float: right; 61 | } 62 | 63 | /* Set width and height of element to that of its parent */ 64 | .full-size{ 65 | height: 100%; 66 | width: 100%; 67 | } 68 | 69 | /* Position element absolutely to 0,0 */ 70 | .absolute-default{ 71 | position: absolute; 72 | left: 0; 73 | top: 0; 74 | } 75 | 76 | /* Position element absolutely and set its width and height to that of its parent (useful for slideshows) */ 77 | .absolute-fullsize{ 78 | .absolute-default; 79 | .full-size; 80 | } 81 | 82 | /* The micro clearfix http://nicolasgallagher.com/micro-clearfix-hack/ */ 83 | .clearfix { 84 | *zoom:1; 85 | 86 | &:before, 87 | &:after { 88 | content:""; 89 | display:table; 90 | } 91 | &:after { 92 | clear:both; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /styles/base/prefixer.less: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------- 2 | LESS Prefixer 3 | --------------------------------------------------- 4 | 5 | All of the CSS3 fun, none of the prefixes! 6 | 7 | As a rule, you can use the CSS properties you 8 | would expect just by adding a '.': 9 | 10 | box-shadow => .box-shadow(@args) 11 | 12 | Also, when shorthand is available, arguments are 13 | not parameterized. Learn CSS, not LESS Prefixer. 14 | 15 | ------------------------------------------------- 16 | TABLE OF CONTENTS 17 | (*) denotes a syntax-sugar helper 18 | ------------------------------------------------- 19 | 20 | .animation(@args) 21 | .animation-delay(@delay) 22 | .animation-direction(@direction) 23 | .animation-duration(@duration) 24 | .animation-iteration-count(@count) 25 | .animation-name(@name) 26 | .animation-play-state(@state) 27 | .animation-timing-function(@function) 28 | .background-size(@args) 29 | .border-radius(@args) 30 | .box-shadow(@args) 31 | .inner-shadow(@args) * 32 | .box-sizing(@args) 33 | .border-box() * 34 | .content-box() * 35 | .columns(@args) 36 | .column-count(@count) 37 | .column-gap(@gap) 38 | .column-rule(@args) 39 | .column-width(@width) 40 | .gradient(@default,@start,@stop) * 41 | .linear-gradient-top(@default,@color1,@stop1,@color2,@stop2,[@color3,@stop3,@color4,@stop4])* 42 | .linear-gradient-left(@default,@color1,@stop1,@color2,@stop2,[@color3,@stop3,@color4,@stop4])* 43 | .opacity(@factor) 44 | .transform(@args) 45 | .rotate(@deg) 46 | .scale(@factor) 47 | .translate(@x,@y) 48 | .translate3d(@x,@y,@z) 49 | .translateHardware(@x,@y) * 50 | .text-shadow(@args) 51 | .transition(@args) 52 | .transition-delay(@delay) 53 | .transition-duration(@duration) 54 | .transition-property(@property) 55 | .transition-timing-function(@function) 56 | 57 | 58 | 59 | Credit to LESS Elements for the motivation and 60 | to CSS3Please.com for implementation. 61 | 62 | Copyright (c) 2012 Joel Sutherland 63 | MIT Licensed: 64 | http://www.opensource.org/licenses/mit-license.php 65 | 66 | -----------------------------------------------------*/ 67 | 68 | 69 | /* Animation */ 70 | .animation(@args) { 71 | -webkit-animation: @args; 72 | -moz-animation: @args; 73 | -ms-animation: @args; 74 | -o-animation: @args; 75 | } 76 | .animation-delay(@delay) { 77 | -webkit-animation-delay: @delay; 78 | -moz-animation-delay: @delay; 79 | -ms-animation-delay: @delay; 80 | -o-animation-delay: @delay; 81 | } 82 | .animation-direction(@direction) { 83 | -webkit-animation-direction: @direction; 84 | -moz-animation-direction: @direction; 85 | -ms-animation-direction: @direction; 86 | -o-animation-direction: @direction; 87 | } 88 | .animation-duration(@duration) { 89 | -webkit-animation-duration: @duration; 90 | -moz-animation-duration: @duration; 91 | -ms-animation-duration: @duration; 92 | -o-animation-duration: @duration; 93 | } 94 | .animation-iteration-count(@count) { 95 | -webkit-animation-iteration-count: @count; 96 | -moz-animation-iteration-count: @count; 97 | -ms-animation-iteration-count: @count; 98 | -o-animation-iteration-count: @count; 99 | } 100 | .animation-name(@name) { 101 | -webkit-animation-name: @name; 102 | -moz-animation-name: @name; 103 | -ms-animation-name: @name; 104 | -o-animation-name: @name; 105 | } 106 | .animation-play-state(@state) { 107 | -webkit-animation-play-state: @state; 108 | -moz-animation-play-state: @state; 109 | -ms-animation-play-state: @state; 110 | -o-animation-play-state: @state; 111 | } 112 | .animation-timing-function(@function) { 113 | -webkit-animation-timing-function: @function; 114 | -moz-animation-timing-function: @function; 115 | -ms-animation-timing-function: @function; 116 | -o-animation-timing-function: @function; 117 | } 118 | 119 | 120 | /* Background Size */ 121 | 122 | .background-size(@args) { 123 | -webkit-background-size: @args; 124 | -moz-background-size: @args; 125 | background-size: @args; 126 | } 127 | 128 | 129 | /* Border Radius */ 130 | 131 | .border-radius(@args) { 132 | -webkit-border-radius: @args; 133 | -moz-border-radius: @args; 134 | border-radius: @args; 135 | 136 | -webkit-background-clip: padding-box; 137 | -moz-background-clip: padding; 138 | background-clip: padding-box; 139 | } 140 | 141 | 142 | /* Box Shadows */ 143 | .box-shadow(@args) { 144 | -webkit-box-shadow: @args; 145 | -moz-box-shadow: @args; 146 | box-shadow: @args; 147 | } 148 | .inner-shadow(@args) { 149 | .box-shadow(inset @args); 150 | } 151 | 152 | 153 | /* Box Sizing */ 154 | .box-sizing(@args){ 155 | -webkit-box-sizing: @args; 156 | -moz-box-sizing: @args; 157 | box-sizing: @args; 158 | } 159 | .border-box(){ 160 | .box-sizing(border-box); 161 | } 162 | .content-box(){ 163 | .box-sizing(content-box); 164 | } 165 | 166 | 167 | 168 | /* Columns */ 169 | .columns(@args){ 170 | -webkit-columns: @args; 171 | -moz-columns: @args; 172 | columns: @args; 173 | } 174 | .column-count(@count) { 175 | -webkit-column-count: @count; 176 | -moz-column-count: @count; 177 | column-count: @count; 178 | } 179 | .column-gap(@gap) { 180 | -webkit-column-gap: @gap; 181 | -moz-column-gap: @gap; 182 | column-gap: @gap; 183 | } 184 | .column-width(@width){ 185 | -webkit-column-width: @width; 186 | -moz-column-width: @width; 187 | column-width: @width; 188 | } 189 | .column-rule(@args){ 190 | -webkit-column-rule: @rule; 191 | -moz-column-rule: @rule; 192 | column-rule: @rule; 193 | } 194 | 195 | 196 | /* Gradients */ 197 | .gradient(@default: #F5F5F5, @start: #EEE, @stop: #FFF) { 198 | .linear-gradient-top(@default,@start,0%,@stop,100%); 199 | } 200 | .linear-gradient-top(@default,@color1,@stop1,@color2,@stop2) { 201 | background-color: @default; 202 | background-image: -webkit-gradient(linear, left top, left bottom, color-stop(@stop1, @color1), color-stop(@stop2 @color2)); 203 | background-image: -webkit-linear-gradient(top, @color1 @stop1, @color2 @stop2); 204 | background-image: -moz-linear-gradient(top, @color1 @stop1, @color2 @stop2); 205 | background-image: -ms-linear-gradient(top, @color1 @stop1, @color2 @stop2); 206 | background-image: -o-linear-gradient(top, @color1 @stop1, @color2 @stop2); 207 | background-image: linear-gradient(top, @color1 @stop1, @color2 @stop2); 208 | } 209 | .linear-gradient-top(@default,@color1,@stop1,@color2,@stop2,@color3,@stop3) { 210 | background-color: @default; 211 | background-image: -webkit-gradient(linear, left top, left bottom, color-stop(@stop1, @color1), color-stop(@stop2 @color2), color-stop(@stop3 @color3)); 212 | background-image: -webkit-linear-gradient(top, @color1 @stop1, @color2 @stop2, @color3 @stop3); 213 | background-image: -moz-linear-gradient(top, @color1 @stop1, @color2 @stop2, @color3 @stop3); 214 | background-image: -ms-linear-gradient(top, @color1 @stop1, @color2 @stop2, @color3 @stop3); 215 | background-image: -o-linear-gradient(top, @color1 @stop1, @color2 @stop2, @color3 @stop3); 216 | background-image: linear-gradient(top, @color1 @stop1, @color2 @stop2, @color3 @stop3); 217 | } 218 | .linear-gradient-top(@default,@color1,@stop1,@color2,@stop2,@color3,@stop3,@color4,@stop4) { 219 | background-color: @default; 220 | background-image: -webkit-gradient(linear, left top, left bottom, color-stop(@stop1, @color1), color-stop(@stop2 @color2), color-stop(@stop3 @color3), color-stop(@stop4 @color4)); 221 | background-image: -webkit-linear-gradient(top, @color1 @stop1, @color2 @stop2, @color3 @stop3, @color4 @stop4); 222 | background-image: -moz-linear-gradient(top, @color1 @stop1, @color2 @stop2, @color3 @stop3, @color4 @stop4); 223 | background-image: -ms-linear-gradient(top, @color1 @stop1, @color2 @stop2, @color3 @stop3, @color4 @stop4); 224 | background-image: -o-linear-gradient(top, @color1 @stop1, @color2 @stop2, @color3 @stop3, @color4 @stop4); 225 | background-image: linear-gradient(top, @color1 @stop1, @color2 @stop2, @color3 @stop3, @color4 @stop4); 226 | } 227 | .linear-gradient-left(@default,@color1,@stop1,@color2,@stop2) { 228 | background-color: @default; 229 | background-image: -webkit-gradient(linear, left top, left top, color-stop(@stop1, @color1), color-stop(@stop2 @color2)); 230 | background-image: -webkit-linear-gradient(left, @color1 @stop1, @color2 @stop2); 231 | background-image: -moz-linear-gradient(left, @color1 @stop1, @color2 @stop2); 232 | background-image: -ms-linear-gradient(left, @color1 @stop1, @color2 @stop2); 233 | background-image: -o-linear-gradient(left, @color1 @stop1, @color2 @stop2); 234 | background-image: linear-gradient(left, @color1 @stop1, @color2 @stop2); 235 | } 236 | .linear-gradient-left(@default,@color1,@stop1,@color2,@stop2,@color3,@stop3) { 237 | background-color: @default; 238 | background-image: -webkit-gradient(linear, left top, left top, color-stop(@stop1, @color1), color-stop(@stop2 @color2), color-stop(@stop3 @color3)); 239 | background-image: -webkit-linear-gradient(left, @color1 @stop1, @color2 @stop2, @color3 @stop3); 240 | background-image: -moz-linear-gradient(left, @color1 @stop1, @color2 @stop2, @color3 @stop3); 241 | background-image: -ms-linear-gradient(left, @color1 @stop1, @color2 @stop2, @color3 @stop3); 242 | background-image: -o-linear-gradient(left, @color1 @stop1, @color2 @stop2, @color3 @stop3); 243 | background-image: linear-gradient(left, @color1 @stop1, @color2 @stop2, @color3 @stop3); 244 | } 245 | .linear-gradient-left(@default,@color1,@stop1,@color2,@stop2,@color3,@stop3,@color4,@stop4) { 246 | background-color: @default; 247 | background-image: -webkit-gradient(linear, left top, left top, color-stop(@stop1, @color1), color-stop(@stop2 @color2), color-stop(@stop3 @color3), color-stop(@stop4 @color4)); 248 | background-image: -webkit-linear-gradient(left, @color1 @stop1, @color2 @stop2, @color3 @stop3, @color4 @stop4); 249 | background-image: -moz-linear-gradient(left, @color1 @stop1, @color2 @stop2, @color3 @stop3, @color4 @stop4); 250 | background-image: -ms-linear-gradient(left, @color1 @stop1, @color2 @stop2, @color3 @stop3, @color4 @stop4); 251 | background-image: -o-linear-gradient(left, @color1 @stop1, @color2 @stop2, @color3 @stop3, @color4 @stop4); 252 | background-image: linear-gradient(left, @color1 @stop1, @color2 @stop2, @color3 @stop3, @color4 @stop4); 253 | } 254 | 255 | 256 | /* Opacity */ 257 | .opacity(@factor){ 258 | opacity: @factor; 259 | @iefactor: @factor*100; 260 | filter: alpha(opacity=@iefactor); 261 | } 262 | 263 | 264 | /* Text Shadow */ 265 | .text-shadow(@args){ 266 | text-shadow: @args; 267 | } 268 | 269 | /* Transforms */ 270 | 271 | .transform(@args) { 272 | -webkit-transform: @args; 273 | -moz-transform: @args; 274 | -ms-transform: @args; 275 | -o-transform: @args; 276 | transform: @args; 277 | } 278 | .rotate(@deg:45deg){ 279 | .transform(rotate(@deg)); 280 | } 281 | .scale(@factor:.5){ 282 | .transform(scale(@factor)); 283 | } 284 | .translate(@x,@y){ 285 | .transform(translate(@x,@y)); 286 | } 287 | .translate3d(@x,@y,@z) { 288 | .transform(translate3d(@x,@y,@z)); 289 | } 290 | .translateHardware(@x,@y){ 291 | .translate(@x,@y); 292 | -webkit-transform: translate3d(@x,@y,0); 293 | -moz-transform: translate3d(@x,@y,0); 294 | } 295 | 296 | 297 | /* Transitions */ 298 | 299 | .transition(@args:200ms) { 300 | -webkit-transition: @args; 301 | -moz-transition: @args; 302 | -o-transition: @args; 303 | transition: @args; 304 | } 305 | .transition-delay(@delay:0) { 306 | -webkit-transition-delay: @delay; 307 | -moz-transition-delay: @delay; 308 | -o-transition-delay: @delay; 309 | transition-delay: @delay; 310 | } 311 | .transition-duration(@duration:200ms) { 312 | -webkit-transition-duration: @duration; 313 | -moz-transition-duration: @duration; 314 | -o-transition-duration: @duration; 315 | transition-duration: @duration; 316 | } 317 | .transition-property(@property:all) { 318 | -webkit-transition-property: @property; 319 | -moz-transition-property: @property; 320 | -o-transition-property: @property; 321 | transition-property: @property; 322 | } 323 | .transition-timing-function(@function:ease) { 324 | -webkit-transition-timing-function: @function; 325 | -moz-transition-timing-function: @function; 326 | -o-transition-timing-function: @function; 327 | transition-timing-function: @function; 328 | } -------------------------------------------------------------------------------- /styles/base/reset.less: -------------------------------------------------------------------------------- 1 | /** 2 | * html5doctor.com Reset Stylesheet 3 | * v1.6.1 4 | * Last Updated: 2010-09-17 5 | * Author: Richard Clark - http://richclarkdesign.com 6 | * Twitter: @rich_clark 7 | */ 8 | 9 | html, body, div, span, object, iframe, 10 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 11 | abbr, address, cite, code, 12 | del, dfn, em, img, ins, kbd, q, samp, 13 | small, strong, sub, sup, var, 14 | b, i, 15 | dl, dt, dd, ol, ul, li, 16 | fieldset, form, label, legend, 17 | table, caption, tbody, tfoot, thead, tr, th, td, 18 | article, aside, canvas, details, figcaption, figure, 19 | footer, header, hgroup, menu, nav, section, summary, 20 | time, mark, audio, video { 21 | margin:0; 22 | padding:0; 23 | border:0; 24 | outline:0; 25 | font-size:100%; 26 | vertical-align:baseline; 27 | background:transparent; 28 | } 29 | 30 | body { 31 | line-height:1; 32 | } 33 | 34 | article,aside,details,figcaption,figure, 35 | footer,header,hgroup,menu,nav,section { 36 | display:block; 37 | } 38 | 39 | nav ul { 40 | list-style:none; 41 | } 42 | 43 | blockquote, q { 44 | quotes:none; 45 | } 46 | 47 | blockquote:before, blockquote:after, 48 | q:before, q:after { 49 | content:''; 50 | content:none; 51 | } 52 | 53 | a { 54 | margin:0; 55 | padding:0; 56 | font-size:100%; 57 | vertical-align:baseline; 58 | background:transparent; 59 | } 60 | 61 | /* change colours to suit your needs */ 62 | ins { 63 | background-color:#ff9; 64 | color:#000; 65 | text-decoration:none; 66 | } 67 | 68 | /* change colours to suit your needs */ 69 | mark { 70 | background-color:#ff9; 71 | color:#000; 72 | font-style:italic; 73 | font-weight:bold; 74 | } 75 | 76 | del { 77 | text-decoration: line-through; 78 | } 79 | 80 | abbr[title], dfn[title] { 81 | border-bottom:1px dotted; 82 | cursor:help; 83 | } 84 | 85 | table { 86 | border-collapse:collapse; 87 | border-spacing:0; 88 | } 89 | 90 | /* change border colour to suit your needs */ 91 | hr { 92 | display:block; 93 | height:1px; 94 | border:0; 95 | border-top:1px solid #cccccc; 96 | margin:1em 0; 97 | padding:0; 98 | } 99 | 100 | input, select { 101 | vertical-align:middle; 102 | } -------------------------------------------------------------------------------- /styles/base/spacing.less: -------------------------------------------------------------------------------- 1 | /** 2 | * Spacing 3 | * 4 | * This LESS file defines margins and paddings for block-level 5 | * elements. Helper classes are included for use elsewhere 6 | * in site styles. 7 | */ 8 | 9 | /* Settings */ 10 | 11 | @import 'variables.less'; 12 | 13 | /* 14 | @baseline: @baseline; 15 | */ 16 | 17 | /** 18 | * Spacing 19 | * p, m, lh = padding, margin, line-height 20 | * a, t, r, b, l, h, v = all, top, right, bottom, left, horizontal, vertical 21 | * n, h, s, d = none(0px), half(@baseline / 2), single(@baseline), double(@baseline * 2), none(0px) 22 | */ 23 | 24 | .ptn, .pvn, .pan{ 25 | padding-top: 0px !important 26 | } 27 | .pth, .pvh, .pah{ 28 | padding-top: @baseline / 2 !important 29 | } 30 | .pts, .pvs, .pas{ 31 | padding-top: @baseline !important 32 | } 33 | .ptd, .pvd, .pad{ 34 | padding-top: @baseline * 2 !important 35 | } 36 | .prn, .phn, .pan{ 37 | padding-right: 0px !important 38 | } 39 | .prh, .phh, .pah{ 40 | padding-right: @baseline / 2 !important 41 | } 42 | .prs, .phs, .pas{ 43 | padding-right: @baseline !important 44 | } 45 | .prd, .phd, .pad{ 46 | padding-right: @baseline * 2 !important 47 | } 48 | .pbn, .pvn, .pan{ 49 | padding-bottom: 0px !important 50 | } 51 | .pbh, .pvh, .pah{ 52 | padding-bottom: @baseline / 2 !important 53 | } 54 | .pbs, .pvs, .pas{ 55 | padding-bottom: @baseline !important 56 | } 57 | .pbd, .pvd, .pad{ 58 | padding-bottom: @baseline * 2 !important 59 | } 60 | .pln, .phn, .pan{ 61 | padding-left: 0px !important 62 | } 63 | .plh, .phh, .pah{ 64 | padding-left: @baseline / 2 !important 65 | } 66 | .pls, .phs, .pas{ 67 | padding-left: @baseline !important 68 | } 69 | .pld, .phd, .pad{ 70 | padding-left: @baseline * 2 !important 71 | } 72 | .mtn, .mvn, .man{ 73 | margin-top: 0px !important 74 | } 75 | .mth, .mvh, .mah{ 76 | margin-top: @baseline / 2 !important 77 | } 78 | .mts, .mvs, .mas{ 79 | margin-top: @baseline !important 80 | } 81 | .mtd, .mvd, .mad{ 82 | margin-top: @baseline * 2 !important 83 | } 84 | .mrn, .mhn, .man{ 85 | margin-right: 0px !important 86 | } 87 | .mrh, .mhh, .mah{ 88 | margin-right: @baseline / 2 !important 89 | } 90 | .mrs, .mhs, .mas{ 91 | margin-right: @baseline !important 92 | } 93 | .mrd, .mhd, .mad{ 94 | margin-right: @baseline * 2 !important 95 | } 96 | .mbn, .mvn, .man{ 97 | margin-bottom: 0px !important 98 | } 99 | .mbh, .mvh, .mah{ 100 | margin-bottom: @baseline / 2 !important 101 | } 102 | .mbs, .mvs, .mas{ 103 | margin-bottom: @baseline !important 104 | } 105 | .mbd, .mvd, .mad{ 106 | margin-bottom: @baseline * 2 !important 107 | } 108 | .mln, .mhn, .man{ 109 | margin-left: 0px !important 110 | } 111 | .mlh, .mhh, .mah{ 112 | margin-left: @baseline / 2 !important 113 | } 114 | .mls, .mhs, .mas{ 115 | margin-left: @baseline !important 116 | } 117 | .mld, .mhd, .mad{ 118 | margin-left: @baseline * 2 !important 119 | } 120 | .lhh { 121 | line-height: @baseline / 2 !important; 122 | } 123 | .lhs { 124 | line-height: @baseline !important; 125 | } 126 | .lhd { 127 | line-height: @baseline * 2 !important; 128 | } 129 | .lhn { 130 | line-height: 0px !important; 131 | } -------------------------------------------------------------------------------- /styles/base/typography.less: -------------------------------------------------------------------------------- 1 | /** 2 | * Name Here 3 | * 4 | * @version 1.0 5 | * @package Name Here 6 | * @author New Media Campaigns 7 | * @copyright 2012 New Media Campaigns 8 | * @link http://www.newmediacampaigns.com 9 | * 10 | * Copyright (c) 2012 New Media Campaigns 11 | * 12 | * Permission is hereby granted, free of charge, to any person obtaining a copy 13 | * of this software and associated documentation files (the "Software"), to deal 14 | * in the Software without restriction, including without limitation the rights 15 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | * copies of the Software, and to permit persons to whom the Software is furnished 17 | * to do so, subject to the following conditions: 18 | * 19 | * The above copyright notice and this permission notice shall be included in all 20 | * copies or substantial portions of the Software. 21 | * 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 28 | * THE SOFTWARE. 29 | */ 30 | 31 | /** 32 | * Typography 33 | * 34 | * This LESS file defines the baseline, color, font-size, and other typographical 35 | * styles for text elements. 36 | */ 37 | 38 | /* Settings */ 39 | 40 | @import 'variables.less'; 41 | 42 | /* 43 | @baseline: @baseline; 44 | 45 | @body-color: @body-color; 46 | @body-font-family: @body-font-family; 47 | @body-font-size: @body-font-size; 48 | @body-accent-color: @body-accent-color; 49 | 50 | @header-color: @header-clor; 51 | @header-font-family: @header-font-family; 52 | @header-font-weight: @header-font-weight; 53 | */ 54 | 55 | /* Base */ 56 | 57 | html, body { 58 | font-family: @body-font-family; 59 | color: @body-color; 60 | font-size: @body-font-size; 61 | .lhs; 62 | } 63 | 64 | /* Block-level */ 65 | 66 | h1, h2, h3, h4, h5, h6, ul, ol, dl, p, blockquote, table, form, pre{ 67 | .mbs; 68 | } 69 | 70 | /* Headers */ 71 | 72 | .all-headers{ 73 | color: @header-color; 74 | font-family: @header-font-family; 75 | font-weight: @header-font-weight; 76 | } 77 | h1, .alpha{ 78 | .all-headers; 79 | font-size: @body-font-size * 2.5; 80 | .lhd; 81 | } 82 | h2, .beta{ 83 | .all-headers; 84 | font-size: @body-font-size * 1.75; 85 | .lhd; 86 | } 87 | h3, .gamma{ 88 | .all-headers; 89 | font-size: @body-font-size * 1.2; 90 | .lhd; 91 | .mbn; 92 | } 93 | h4, .delta{ 94 | .all-headers; 95 | font-size: @body-font-size * 1; 96 | .lhd; 97 | .mbn; 98 | } 99 | h5, .epsilon{ 100 | .all-headers; 101 | font-size: @body-font-size * 1; 102 | .lhs; 103 | .mbn 104 | } 105 | h6, .zeta{ 106 | .all-headers; 107 | font-size: @body-font-size * 1; 108 | .lhs; 109 | .mbn; 110 | } 111 | 112 | /* Headers (above scale) */ 113 | 114 | .giga{ 115 | .all-headers; 116 | font-size: @body-font-size * 6; 117 | line-height: @baseline * 4; 118 | } 119 | .mega{ 120 | .all-headers; 121 | font-size: @body-font-size * 5; 122 | line-height: @baseline * 3; 123 | } 124 | .kilo{ 125 | .all-headers; 126 | font-size: @body-font-size * 4; 127 | line-height: @baseline * 3; 128 | } 129 | 130 | /* Headers (below scale) */ 131 | 132 | .milli{ 133 | .all-headers; 134 | font-size: @body-font-size * 0.8; 135 | } 136 | 137 | /* Text */ 138 | 139 | a{ 140 | color: @body-accent-color; 141 | } 142 | a:link{ 143 | text-decoration: underline; 144 | } 145 | a:visited{ 146 | 147 | } 148 | a:hover{ 149 | text-decoration: none; 150 | } 151 | a:active{ 152 | 153 | } 154 | a:focus{ 155 | 156 | } 157 | small { 158 | font-size: 80%; 159 | } 160 | sup, sub { 161 | font-size: 80%; 162 | .lhn; 163 | } 164 | sup { 165 | vertical-align: super; 166 | } 167 | sub { 168 | vertical-align: sub; 169 | } 170 | 171 | .lead{ 172 | color: darken(@body-color, 20%); 173 | font-size: @baseline * 0.8; 174 | } 175 | 176 | blockquote{ 177 | border-left: 5px solid fade(#000, 10%); 178 | .mhs; 179 | .pls; 180 | color: lighten(@body-color, 20%); 181 | font-size: @baseline * 0.8; 182 | font-style: italic; 183 | 184 | :last-child{ 185 | .mbn; 186 | } 187 | small{ 188 | color: fade(#000, 50%); 189 | font-size: @baseline * 0.7; 190 | font-style: normal; 191 | } 192 | } 193 | pre, code, kbd{ 194 | background: #F8F8F8; 195 | border: 1px solid #EAEAEA; 196 | .border-radius(3px); 197 | margin: 0 2px; 198 | padding: 0 5px; 199 | font-family: Consolas, "Courier New", Courier, mono; 200 | font-size: @body-font-size * 0.9; 201 | color: @body-color; 202 | word-wrap: break-word; 203 | } 204 | pre{ 205 | .mhs; 206 | .pah; 207 | 208 | code{ 209 | border: none; 210 | .man; 211 | .pan; 212 | } 213 | } 214 | a code{ 215 | background: none; 216 | border: none; 217 | .pan; 218 | .man; 219 | } 220 | strong{ 221 | font-weight: bold; 222 | } 223 | em{ 224 | font-style: italic; 225 | } 226 | ol, ul, dl{ 227 | .mls; 228 | .pls; 229 | ol,ul { 230 | .mbn; 231 | } 232 | } 233 | dt{ 234 | font-weight: bold; 235 | } 236 | dd{ 237 | .mls; 238 | } 239 | 240 | .table{ 241 | border-collapse: collapse; 242 | border-spacing: 0; 243 | width: 100%; 244 | } 245 | .table th, .table td{ 246 | border-top: 1px solid fade(#000, 10%); 247 | padding: 8px; 248 | text-align: left; 249 | } 250 | .table thead th{ 251 | vertical-align: bottom; 252 | font-weight: bold; 253 | } 254 | .table thead tr:first-child th{ 255 | border-top: none; 256 | } 257 | .table-bordered{ 258 | border: 1px solid fade(#000, 10%); 259 | border-collapse: separate; 260 | border-left: none; 261 | .border-radius(4px); 262 | 263 | th, td{ 264 | border-left: 1px solid fade(#000, 10%); 265 | } 266 | thead:last-child tr:last-child th:first-child, 267 | tbody:last-child tr:last-child td:first-child{ 268 | .border-radius(0 0 0 4px); 269 | } 270 | } 271 | .table-striped{ 272 | tbody tr:nth-child(odd) td{ 273 | background: fade(@body-accent-color, 4%); 274 | } 275 | } 276 | 277 | /* ========================================================================== 278 | Alerts 279 | ========================================================================== */ 280 | 281 | .alert{ 282 | background: #FCF8E3; 283 | border: 1px solid #FBEED5; 284 | .border-radius(4px); 285 | .mbs; 286 | .pah; 287 | color: #C09853; 288 | } 289 | .alert-success{ 290 | .alert; 291 | background-color: #DFF0D8; 292 | border-color: #D6E9C6; 293 | color: #468847; 294 | } 295 | .alert-error{ 296 | .alert; 297 | background-color: #F2DEDE; 298 | border-color: #EED3D7; 299 | color: #B94A48; 300 | } 301 | .alert-info{ 302 | .alert; 303 | background-color: #D9EDF7; 304 | border-color: #BCE8F1; 305 | color: #3A87AD; 306 | } 307 | 308 | /* ========================================================================== 309 | Forms 310 | ========================================================================== */ 311 | 312 | label{ 313 | display: block; 314 | font-weight: bold; 315 | 316 | .req{ 317 | color: @body-accent-color; 318 | font-weight: bold; 319 | } 320 | } 321 | input.text, 322 | textarea, 323 | select, 324 | .radio-group, 325 | .checkbox-group{ 326 | .mbs; 327 | } 328 | input.text, textarea{ 329 | .no-form; 330 | background: #EEE; 331 | border: 1px solid #CCC; 332 | .border-box; 333 | .border-radius(4px); 334 | .inner-shadow(fade(#000, 10%) 0 1px 3px); 335 | height: @baseline * 1.5; 336 | .pah; 337 | width: 100%; 338 | } 339 | textarea{ 340 | height: @baseline * 6; 341 | } 342 | select{ 343 | min-width: 30%; 344 | } 345 | .checkbox-group label, 346 | .radio-group label{ 347 | font-weight: normal; 348 | } 349 | .error{ 350 | background-color: #F2DEDE !important; 351 | border-color: red !important; 352 | outline-color: red !important; 353 | color: red !important; 354 | } 355 | -------------------------------------------------------------------------------- /styles/base/variables.less: -------------------------------------------------------------------------------- 1 | /* ========================================================================== 2 | Spacing 3 | ========================================================================== */ 4 | 5 | @baseline: 20px; 6 | 7 | /* ========================================================================== 8 | Typography 9 | ========================================================================== */ 10 | 11 | @body-color: #555; 12 | @body-font-family: "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, "Lucida Grande", sans-serif; 13 | @body-font-size: 14px; 14 | @body-accent-color: #f00; 15 | 16 | @header-color: #000; 17 | @header-font-family: "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, "Lucida Grande", sans-serif; 18 | @header-font-weight: bold; 19 | 20 | /* ========================================================================== 21 | Grid 22 | ========================================================================== */ 23 | 24 | @fixed-column-width: 40px; 25 | @fixed-gutter-width: 20px; 26 | @fixed-columns: 12; 27 | 28 | @fluid-column-width: 4.3%; 29 | @fluid-gutter-width: 4.4%; 30 | @fluid-columns: 12; 31 | 32 | @mobile-break-width: 480px; 33 | @mobile-column-width: 20%; 34 | @mobile-gutter-width: 6.6666%; 35 | @mobile-columns: 4; 36 | 37 | /* ========================================================================== 38 | Buttons 39 | ========================================================================== */ 40 | 41 | @button-color: #DDD; 42 | @button-primary-color: #0055CC; 43 | @button-info-color: #2F96B4; 44 | @button-success-color: #51A351; 45 | @button-warning-color: #FAA732; 46 | @button-danger-color: #BD362F; 47 | 48 | /* ========================================================================== 49 | Site Variables 50 | ========================================================================== */ 51 | 52 | @import "../site/variables"; -------------------------------------------------------------------------------- /styles/site/site-content.less: -------------------------------------------------------------------------------- 1 | .site-content{ 2 | padding: 20px 40px 40px 320px; 3 | 4 | h1{ 5 | clear: both; 6 | } 7 | } 8 | .interior-site-content{ 9 | .pad; 10 | } 11 | .top{ 12 | background: #333; 13 | display: inline-block; 14 | float: right; 15 | margin-right: -40px; 16 | padding: 4px 8px; 17 | color: #FFF; 18 | font-size: 12px; 19 | text-decoration: none !important; 20 | } 21 | -------------------------------------------------------------------------------- /styles/site/site-footer.less: -------------------------------------------------------------------------------- 1 | .site-footer{ 2 | clear: both; 3 | .ptd; 4 | font-size: 13px; 5 | text-align: center; 6 | } 7 | .site-footer img{ 8 | margin-left: 2px; 9 | position: relative; 10 | top: -2px; 11 | vertical-align: middle; 12 | } 13 | .site-footer ul{ 14 | list-style: none; 15 | .mhn; 16 | .phn; 17 | } 18 | -------------------------------------------------------------------------------- /styles/site/site-header.less: -------------------------------------------------------------------------------- 1 | .site-header{ 2 | position: relative; 3 | z-index: 1; 4 | text-align: center; 5 | } 6 | .site-title{ 7 | .mbn; 8 | font-family: 'Alfa Slab One'; 9 | font-size: @baseline * 4; 10 | font-weight: normal !important; 11 | line-height: @baseline * 5 !important; 12 | 13 | a{ 14 | text-decoration: none; 15 | } 16 | } 17 | .site-slogan{ 18 | font-weight: normal; 19 | } 20 | .fork-me, .fork-me img{ 21 | position: absolute; 22 | top: 0; 23 | right: 0; 24 | } 25 | .fork-me{ 26 | z-index: 2; 27 | } 28 | 29 | .interior-site-header{ 30 | background: #EEE; 31 | .inner-shadow(fade(#000, 7%) 0 0 40px); 32 | .pas; 33 | text-align: center; 34 | 35 | .site-title{ 36 | font-size: @baseline * 2; 37 | line-height: @baseline * 2 !important; 38 | } 39 | .site-slogan{ 40 | .mbs; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /styles/site/site-navigation.less: -------------------------------------------------------------------------------- 1 | .site-navigation{ 2 | background: #EEE; 3 | .inner-shadow(fade(#000, 7%) 0 0 40px); 4 | .pas; 5 | position: fixed; 6 | top: 0; 7 | bottom: 0; 8 | overflow: auto; 9 | width: 240px; 10 | } 11 | .build-date{ 12 | .mbs; 13 | color: #AAA; 14 | font-family: Helvetica, Arial, sans-serif; 15 | font-size: 11px; 16 | } 17 | .site-navigation ul{ 18 | .man; 19 | .pan; 20 | .no-list; 21 | font-size: 16px; 22 | } 23 | .site-navigation > ul > li{ 24 | margin-bottom: 10px; 25 | } 26 | .site-navigation a{ 27 | text-decoration: underline; 28 | 29 | &:hover{ 30 | text-decoration: none; 31 | } 32 | } 33 | .site-navigation a.active{ 34 | background-color: #ff9; 35 | } 36 | .site-navigation ul ul{ 37 | .mls; 38 | .pth; 39 | font-size: 12px; 40 | 41 | a{ 42 | text-decoration: none; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /styles/site/variables.less: -------------------------------------------------------------------------------- 1 | /* ========================================================================== 2 | Spacing 3 | ========================================================================== */ 4 | 5 | @baseline: 20px; 6 | 7 | /* ========================================================================== 8 | Typography 9 | ========================================================================== */ 10 | 11 | @body-color: #666; 12 | @body-font-family: Georgia, "Times New Roman", Times, serif; 13 | @body-font-size: 14px; 14 | @body-accent-color: #000; 15 | 16 | @header-color: #111; 17 | @header-font-family: Georgia, "Times New Roman", Times, serif; 18 | @header-font-weight: 700; 19 | 20 | /* ========================================================================== 21 | Grid 22 | ========================================================================== */ 23 | 24 | @fixed-column-width: 60px; 25 | @fixed-gutter-width: 20px; 26 | @fixed-columns: 12; 27 | 28 | @fluid-column-width: 4.3%; 29 | @fluid-gutter-width: 4.4%; 30 | @fluid-columns: 12; 31 | 32 | @mobile-break-width: 480px; 33 | @mobile-column-width: 20%; 34 | @mobile-gutter-width: 6.6666%; 35 | @mobile-columns: 4; 36 | 37 | /* ========================================================================== 38 | Buttons 39 | ========================================================================== */ 40 | 41 | @button-color: #DDD; 42 | @button-primary-color: #0055CC; 43 | @button-info-color: #2F96B4; 44 | @button-success-color: #51A351; 45 | @button-warning-color: #FAA732; 46 | @button-danger-color: #BD362F; 47 | -------------------------------------------------------------------------------- /styles/syntax.css: -------------------------------------------------------------------------------- 1 | .highlight { background: #ffffff; } 2 | .highlight .c { color: #999988; font-style: italic } /* Comment */ 3 | .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ 4 | .highlight .k { font-weight: bold } /* Keyword */ 5 | .highlight .o { font-weight: bold } /* Operator */ 6 | .highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */ 7 | .highlight .cp { color: #999999; font-weight: bold } /* Comment.Preproc */ 8 | .highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */ 9 | .highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */ 10 | .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ 11 | .highlight .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */ 12 | .highlight .ge { font-style: italic } /* Generic.Emph */ 13 | .highlight .gr { color: #aa0000 } /* Generic.Error */ 14 | .highlight .gh { color: #999999 } /* Generic.Heading */ 15 | .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ 16 | .highlight .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */ 17 | .highlight .go { color: #888888 } /* Generic.Output */ 18 | .highlight .gp { color: #555555 } /* Generic.Prompt */ 19 | .highlight .gs { font-weight: bold } /* Generic.Strong */ 20 | .highlight .gu { color: #aaaaaa } /* Generic.Subheading */ 21 | .highlight .gt { color: #aa0000 } /* Generic.Traceback */ 22 | .highlight .kc { font-weight: bold } /* Keyword.Constant */ 23 | .highlight .kd { font-weight: bold } /* Keyword.Declaration */ 24 | .highlight .kp { font-weight: bold } /* Keyword.Pseudo */ 25 | .highlight .kr { font-weight: bold } /* Keyword.Reserved */ 26 | .highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */ 27 | .highlight .m { color: #009999 } /* Literal.Number */ 28 | .highlight .s { color: #d14 } /* Literal.String */ 29 | .highlight .na { color: #008080 } /* Name.Attribute */ 30 | .highlight .nb { color: #0086B3 } /* Name.Builtin */ 31 | .highlight .nc { color: #445588; font-weight: bold } /* Name.Class */ 32 | .highlight .no { color: #008080 } /* Name.Constant */ 33 | .highlight .ni { color: #800080 } /* Name.Entity */ 34 | .highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */ 35 | .highlight .nf { color: #990000; font-weight: bold } /* Name.Function */ 36 | .highlight .nn { color: #555555 } /* Name.Namespace */ 37 | .highlight .nt { color: #000080 } /* Name.Tag */ 38 | .highlight .nv { color: #008080 } /* Name.Variable */ 39 | .highlight .ow { font-weight: bold } /* Operator.Word */ 40 | .highlight .w { color: #bbbbbb } /* Text.Whitespace */ 41 | .highlight .mf { color: #009999 } /* Literal.Number.Float */ 42 | .highlight .mh { color: #009999 } /* Literal.Number.Hex */ 43 | .highlight .mi { color: #009999 } /* Literal.Number.Integer */ 44 | .highlight .mo { color: #009999 } /* Literal.Number.Oct */ 45 | .highlight .sb { color: #d14 } /* Literal.String.Backtick */ 46 | .highlight .sc { color: #d14 } /* Literal.String.Char */ 47 | .highlight .sd { color: #d14 } /* Literal.String.Doc */ 48 | .highlight .s2 { color: #d14 } /* Literal.String.Double */ 49 | .highlight .se { color: #d14 } /* Literal.String.Escape */ 50 | .highlight .sh { color: #d14 } /* Literal.String.Heredoc */ 51 | .highlight .si { color: #d14 } /* Literal.String.Interpol */ 52 | .highlight .sx { color: #d14 } /* Literal.String.Other */ 53 | .highlight .sr { color: #009926 } /* Literal.String.Regex */ 54 | .highlight .s1 { color: #d14 } /* Literal.String.Single */ 55 | .highlight .ss { color: #990073 } /* Literal.String.Symbol */ 56 | .highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */ 57 | .highlight .vc { color: #008080 } /* Name.Variable.Class */ 58 | .highlight .vg { color: #008080 } /* Name.Variable.Global */ 59 | .highlight .vi { color: #008080 } /* Name.Variable.Instance */ 60 | .highlight .il { color: #009999 } /* Literal.Number.Integer.Long */ --------------------------------------------------------------------------------