Skocz do zawartości

Witaj na forum webmasterów Webax.pl.

Wyświetl nową zawartość

Thelleo

Thelleo

Rejestracja: 17 lip 2012
Poza forum Ostatnio: 07 paź 2013 13:40
-----

#4730 Podstawy bezpieczeństwa w skryptach PHP. SQL Injection i XSS.

Napisane przez Thelleo w 03 styczeń 2013 - 16:12

PHP jest prawdopodobnie najpopularniejszym językiem do tworzeniach dynamicznych stron i skryptów wśród początkujących. W internecie jest bardzo dużo kursów i poradników a sam język jest instalowany na praktycznie każdym hostingu (najczęściej w wersji 5.3 lub 5.2, chociaż ja preferuję najnowsze 5.4, które ma trochę feature-ów).

Z tego powodu PHP w oczach "większych developerów" jest widziany jako dość kiepski język, bo internet oblega masa dziurawych skryptów i systemów pisanych przez osoby początkujące. Osobiście nie potępiam tego, bo pamiętam jak sam uczyłem się PHP. W kursach albo autorzy nie wspominali o bezpieczeństwie, albo były to krótkie nic nie mówiące notki (no bo początkujący nie koniecznie wie czym jest SQL Injection lub XSS). Chciałbym w tym temacie zaprezentować sposoby ochrony swoich skryptów a przy okazji uświadomić "nowych" jak łatwo można złamać niektóre rzeczy i do jakich nieprzyjemności może to doprowadzić (no bo przecież dziura wykorzystana przez crackera w skrypcie za który ktoś zapłacił powiedzmy 1000 zł może być ogromnym ciosem dla reputacji developera).

A więc zaczynamy, na początku zacznę od czegoś co można najczęściej spotkać u początkujących, czyli całkowite zaufanie dla danych od użytkownika i przekazywanie ich bezpośrednio do zapytania.

SQL Injection

Atak SQL Injection polega na wrzuceniu do zapytania SQL wywoływanego przez skrypt PHP własnych danych i tym samym manipulowaniu jego wynikiem. Załóżmy, że mamy stronę gdzie użytkownicy mogą pisać na własnych blogach. Mamy 2 tabele - jedną na użytkowników, drugą na wpisy a wyświetlanie pojedynczego wpisu opiera się o coś w stylu show.php?id=666.

Przeciętny (i podatny) kod który takie coś robi:


$id = @$_GET['id'];
$query = mysql_query("SELECT title, content FROM articles WHERE id = {$id}");
$data = mysql_fetch_array($query);
echo '<h1>'.$data['title'].'</h1>';
echo '<p>'.$data['content'].'</p>';

Jak widzimy najpierw pobieramy z tablicy $_GET identyfikator newsa i wrzucamy go na koniec zapytania. Taka metoda zadziała i wyświetli artykuł poniżej, ale... no właśnie! Ale!
Każdy odwiedzający będzie mógł pod $id podstawić cokolwiek. Zaraz pokażę Ci co dzięki temu można z tej strony wydobyć, ale najpierw jedna żelazna zasada: nigdy nie ufaj danym od użytkownika. NIGDY!

A więc tak, aby wyświetlić news o ID 666 wchodzimy na adres: show.php?id=666. Wpis się pokaże, ale wiesz co się stanie jeżeli wpiszemy coś takiego?

show.php?id=666 UNION SELECT username, password FROM users WHERE username = 'admin' --

Wtedy finalne zapytanie będzie wyglądało tak:

SELECT title, content FROM articles WHERE id = 666 UNION SELECT username, password FROM users WHERE username = 'admin' -- 

UNION SELECT jest konstrukcją która pozwala nadpisać dane pobrane przez pierwszą cześć zapytania danymi z drugiej. Tak, dobrze przeczytałeś - nadpisać. Po takim zapytaniu zamiast tytułu i treści wpisu wyświetliły by się takie dane jak nazwa użytkownika oraz hasła (nawet wyciek hasha może mieć katastrofalne skutki). Brzmi strasznie? Teraz wyobraź sobie, że masz w takim serwisie bloga. Hasła są niehashowane (trzymane czystym tekstem w bazie danych) i ktoś za pomocą tej luki wykrada dane twoje oraz innych użytkowników. Byłbyś szczęśliwy jakby twoje hasło znalazło się w rękach crackera przez błąd programisty?

Pamiętaj, że prowadząc serwis, gdzie użytkownicy się mogą zarejestrować jesteś za ich dane odpowiedzialny. Nie możesz dopuścić do sytuacji żeby wyciekły one w jakikolwiek sposób bo możesz wtedy stracić zaufanie ludzi, którzy do tej pory odwiedzali twój serwis z uśmiechem.

No dobra, ale jak to naprawić?

W bardzo prosty sposób. Jeżeli masz czas i chcesz skorzystać z nowocześniejszego rozwiązania to polecam przenieś swoją obsługę bazy danych na PDO i prepared statements, ale jeżeli chcesz szybko coś naprawić i nie możesz sobie pozwolić na przepisywanie połowy kodu to oto prosta metoda jak całkowicie zabezpieczyć dane od użytkownika dodawane do zapytania.

$id = @$_GET['id'];
$id = mysql_real_escape_string($id); // ← zmienna $id zostaje przepuszczona przez funkcję mysql_escape_string, która całkowicie ją oczyszcza ze wszystkiego co mogłoby zagrozić naszej bazie danych.
$query = mysql_query("SELECT title, content FROM articles WHERE id = {$id}");
$data = mysql_fetch_array($query);
echo '<h1>'.$data['title'].'</h1>';
echo '<p>'.$data['content'].'</p>';


Poradnik nie został skończony, mam zamiar omówić w nim jeszcze XSSy i być może inne podatności, ale na razie nie mam specjalnie czasu ani chęci na ich opisywanie, jednak gdy tylko skończę to zostaną tutaj opublikowane aktualizacje.

Ze względu na przeznaczenie tego tutoriala pozwalam, a nawet zachęcam wklejać go na inne fora i strony, ale bardzo proszę - jeżeli to robisz to umieść informację o tym, że ja go napisałem i o ile regulamin (tamtego serwisu oczywiście) na to pozwala to umieść link do oryginalnego tematu.


#4223 [MyBB] Katalog Firm by Webax.pl

Napisane przez Thelleo w 02 grudzień 2012 - 18:05

Jak zapewne niektórzy pamiętają Webax.pl poprzednio używał MyBB jako skryptu forum. Został wtedy napisany skrypt katalogu firm dzięki któremu dowolna osoba która otrzymała rangę "Hosting" mogła dodać wizytówkę swojej firmy.

Ponieważ aktualnie ten panel nie jest używany już przez Webaxa to postanowiliśmy udostępnić go całkowicie za darmo naszym użytkownikom. Jest on pisany tylko i wyłącznie pod MyBB, a także nie jest sam w sobie pluginem, ale bardziej niezależnym skryptem korzystającym z udostępnianych przez MyBB bilbiotek.

Jego kod nie jest specjalnie dobry, ponieważ podczas gdy Webax.pl poswstawał to ten skrypt był pisany w pośpiechu na zasadzie "żeby było", jednak mam nadzieję, że nie odstraszy to potencjalnych użytkowników.

Ze względu na to, że skrypt był dedykowany dla Webaxa jego instalacja jest znacznie trudniejsza od instalacji pluginu, ale mam nadzieję, że sobie poradzisz.
Chcę również zauważyć, że skrypt nie będzie dalej rozwijany więc używasz go na własną odpowiedzialność.


Instalacja
  • Pobierz skrypt (http://www.speedysha...Wxd/hosting.php) i wrzuć go do głównego katalogu MyBB.
  • Zaloguj się do swojej bazy danych i wykonaj następujące polecenia:

    CREATE TABLE IF NOT EXISTS `mybb_hosting` (
    `hid` int(11) NOT NULL AUTO_INCREMENT,
    `author_id` int(11) NOT NULL,
    `title` varchar(80) COLLATE utf8_bin NOT NULL,
    `description` text COLLATE utf8_bin NOT NULL,
    `image` varchar(200) COLLATE utf8_bin NOT NULL,
    `address` varchar(80) COLLATE utf8_bin NOT NULL,
    `email` varchar(80) COLLATE utf8_bin NOT NULL,
    `phone` varchar(80) COLLATE utf8_bin NOT NULL,
    `rate` int(11) NOT NULL,
    `rate_number` int(11) NOT NULL,
    `country` varchar(60) COLLATE utf8_bin NOT NULL,
    `zipcode` varchar(20) COLLATE utf8_bin NOT NULL,
    `www` varchar(120) COLLATE utf8_bin NOT NULL,
    `city` varchar(80) COLLATE utf8_bin NOT NULL,
    `about` text COLLATE utf8_bin NOT NULL,
    `type` set('web','game') COLLATE utf8_bin NOT NULL,
    PRIMARY KEY (`hid`)
    ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=1;
    CREATE TABLE IF NOT EXISTS `mybb_hostingrates` (
    `oid` int(11) NOT NULL AUTO_INCREMENT,
    `hosting_id` int(11) NOT NULL,
    `rate1` int(11) NOT NULL,
    `content` text COLLATE utf8_bin NOT NULL,
    `website` varchar(80) COLLATE utf8_bin NOT NULL,
    `author_id` int(11) NOT NULL,
    `time` int(11) NOT NULL,
    `type` set('good','bad') COLLATE utf8_bin NOT NULL,
    `username` varchar(80) COLLATE utf8_bin NOT NULL,
    `rate2` int(11) NOT NULL,
    `rate3` int(11) NOT NULL,
    `rate_all` double NOT NULL,
    PRIMARY KEY (`oid`)
    ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=1;
  • Wejdź do panelu administratora i zakładkę Style i Szablony a następnie w Szablonach utwórz nowy szablon o nazwie "hosting" i wrzuć do niego następującą treść:


    <html>
    <head>
    <title>Hosting - {$mybb->settings['bbname']}</title>
    {$headerinclude}
    {$metag}
    </head>
    <body>
    {$header}
    <br class="clear" />
    <div style="width: 100%;">
    {$content}
    </div>
    <br style="clear: both" />
    {$footer}
    </body>
    </html>
  • Utwórz grupę "Hosting" w panelu administratora i odpowiednio zmodyfikuj 2 linijki w pliku hosting.php:


    $hosting_gid = array(4, 9, 8);
    $admin_gid = array(4, 8);
Znane błędy
  • Skrypt wymaga, aby jego tabele miały prefix "mybb_"
  • W załączonym skrypcie nie jest dostępny widget umieszczony w siedebarze ze względu na to, że on dopisanych bezpośrednio do plików MyBB.
  • Kod HTML jest umieszczony bezpośrednio w pliku hosting.php (to nie jest stricte błąd, ale edycja czegoś takiego nie jest specjalnie przyjemna)

Załączone pliki




#3754 Ruby on Rails - alternatywa PHP - część szósta - walidacja

Napisane przez Thelleo w 17 listopad 2012 - 12:52

Do validates w modelu (dla :username i :email) warto też dodać

:uniqueness => true

żeby nikt nie zarejestrował się dwa razy na te same dane.
Całość u mnie wygląda tak:

class User < ActiveRecord::Base
  attr_accessible :email, :password, :register_date, :username
  validates :username, :uniqueness => true, :presence => true, :length => { :minimum => 3, :maximum => 15 }
  validates :email, :uniqueness => true, :format => { :with => /^[a-zA-Z0-9.\-_]+\@[a-zA-Z0-9.\-_]+\.[a-z]{2,4}$/ }
end



#2981 Jaka to czcionka

Napisane przez Thelleo w 02 listopad 2012 - 22:19

Tak, czcionka to Myriad Pro.


#2705 System pluginów w PHP

Napisane przez Thelleo w 21 październik 2012 - 01:40

Na potrzeby swojego projektu, którym jest CMS chciałem stworzyć do niego mechanizm pluginów za pomocą których będę mógł się wczepiać do różnych funkcji skryptu.
Osobiście uważam, że bardzo przyjemnym w użyciu systemem jest ten umieszczony w MyBB dlatego moja metoda opiera się o podobną ideę.

Ogólnie rzecz biorąc to co teraz chciałbym przedstawić to mój pomysł na niewielki, ale potężny system pluginów opartych o haki za pomocą których możemy wczepić się w każde miejsce w którym programista przewidział możliwość wczepiania.

Klasa ma 2 metody. Pierwsza to register_hook($name, callable $function) za pomocą którego rejestrujemy akcję dla haka. W 1 parametrze wpisujemy nazwę haka, natomiast w drugim nazwę funkcji bądź inną rzecz będącą "callable".
Natomiast drugą metodą jest run_hook($name, $params = NULL) za pomocą której odpalamy funkcje przypisane do danego haka. W pierwszym parametrze znajduje się jego nazwa, natomiast w drugim ewentualne parametry, które chcemy przekazać do funkcji.

No dobrze, po tym krótkim wstępie przyszedł czas na kod opatrzony lekkim komentarze i przykładem zaprezentowanym pod klasą.

/**
* Simple class for basic plugin system based on hooks.
* You can register many function to one hook and run they all with one method.
*
* @author Thelleo
* @see http://youcode.pl
* @version 1.0.0
* @copyright Thelleo © 2012
* @license BSD
*
* @package Curro
* @subpackage Plugin
*/
class Curro_Plugin
{
/**
* List of registered hooks
* @var array
*/
static protected $hooks = array();

/**
* Registering new hook
* @param string $name -- Name of hook
* @param callable $function -- Callable function, you can use name of function in string or anonymous function
*/
static public function register_hook($name, callable $function)
{
self::$hooks[$name][] = $function;
}

/**
* Running functions registered to selected hook.
* @param string $name -- Name of hook to run
* @param mixed $params -- Params passed to functions
*/
static public function run_hook($name, $params = NULL)
{
if(array_key_exists($name, self::$hooks))
{
foreach(self::$hooks[$name] as $hook)
{
$hook($params); // Cool, huh?
}
}
}

}

/**
* TEST
*/

function change_name()
{
// Global needs to be about 20% cooler, but you can live with him.
global $text;
$text = 'Zmieniona nazwa!';
}

Curro_Plugin::register_hook('example_hook', 'change_name');

$text = 'Jestem sobie tekstem, który zostanie zmieniony przez plugin.
';
echo 'Tekst przed aktywacją haka: '.$text.'
';

Curro_Plugin::run_hook('example_hook');

echo 'Tekst po aktywacji haka: '.$text;


?>



#1715 PDO - bazy danych na obiektach

Napisane przez Thelleo w 04 wrzesień 2012 - 14:34

PDO - bazy danych na obiektach

W tym tutorialu chciałbym przedstawić obsługę PDO czyli PHP Data Objects. Jest to biblioteka za pomocą której możemy połączyć się z niemal każdą bazą opartą o język SQL. PDO jest genialnym sterownikiem a, dokumentacja PHP nie zaleca używania zwykłych funkcji typu mysql_query();

Żeby w miarę łatwo poruszać się po PDO programista powinien znać w miarę dobrze programowanie obiektowe.

Połączenie z bazą danych

Połączenie możemy wykonać w następujący sposób.
try 
{
$config = array(
'host' => 'localhost',
'user' => 'użytkownik',
'pass' => 'hasło',
'db' => 'nazwa bazy'
);
$pdo = new PDO("mysql:host={$config['host']};dbname={$config['db']}", $config['user'], $config['pass']);
}
catch (PDOException $e)
{
die('Wystąpił błąd podczas połączenia z bazą danych!');
}

Teorytycznie połączenie można wykonać już dzięki 9-tej linijce, ale dorobiliśmy sobie jeszcze tablicę z danymi oraz obsługę tzw. wyjątków czyli błędów w programowaniu obiektowym.
Wyjątek PDO nazywa się PDOException i to go musimy szukać jeżeli chcemy "złapać" (ang. catch) błąd.

Omówienie podstaw pracy z PDO i podstawowe metody

Po wykonaniu połączenia wg. powyższego kodu zmienna $pdo będzie posiadała nasz obiekt reprezentujący jedno połączenie (nowe połączenie = deklaracja kolejnego obiektu PDO) i umożliwiający odwoływanie się do niego.

Jeżeli programowałeś kiedyś obiektowo w PHP to zapewne wiesz jak odwoływać się od metod w obiektach. W przypadku PDO jest identycznie, czyli:
$pdo->nazwaMetody();

Ze względu na obsługę wyjątków nasz kod może równiesz wyłapywać ewentualne błędy z daną metodą w taki sposób:
try
{
$pdo->nazwaMetody();
}
catch(PDOException $e)
{
die('Wystąpił błąd z PDO: '.$e->getMessage());
}


Podstawowe metody PDO
  • $pdo->query($query)
    Wykonuje zapytanie typu SELECT gdzie parametr $query jest naszym zapytaniem. Zwraca obiekt klasy PDOStatement, który za chwile omówimy.
  • $pdo->exec($query)
    Podobnie jak wyżej z taką różnicą, że to wykonuje zapytanie nie będące SELECTem, ale np. INSERT czy UPDATE. Zwraca ilość zmodyfikowanych wierszy.
  • $pdo->prepare($query, $options = array())
    Tworzy obiekt klasy PDOStatenment, ale go nie wysyła. Jako parametry przyjmuje zapytanie oraz opcje, które w większości przypadków możemy zostawić puste. Za pomocą tego możemy użyć tzw. bindowania czyli bezpiecznego wrzucania danych do zapytania.
Podstawowe metody PDOStatement
  • $pdoStatement->fetch()
    Zwraca element wyniku jako tablicę. Można go używać w pętli while
  • $pdoStatement->fetchAll()
    Zwraca wszystkie elementy jako tablica, którą można użyć w pętli foreach
  • $pdoStatement->bindValue($key, $value, $type = PDO::PARAM_STR)
    Binduje wartość w zapytaniu przygotowanym przez $pdo->prepare(). Jako $key wpisujemy nazwę klucza, którego użyliśmy w zapytaniu, jako $value, wartość, której chcemy użyć, a jako $type wstawiamy jedną ze stałych z typami wspieranymi przez PDO (PDO::PARAM_STR, PDO::PARAM_INT itp.).
    Zostanie to później omówione.
  • $pdoStatement->execute()
    Wykonuje zapytanie, jeżeli zostało spreparowane za pomocą $pdo->prepare()

Wysyłanie zapytań

No cóż... teorii trochę było, ale teraz przechodzimy do praktyki. W tym "rozdziale" pokaże w jaki sposób wykonać zapytania mające na celu wyświetlić lub zmienić poszczególne wiersze w tabeli.

Na początku wyślemy proste zapytanie typu SELECT mające na celu pobranie danych i ich wyświetlenie w formie listy.
$result = $pdo->query('SELECT name, age FROM users WHERE age > 17');
echo '[b]Pełnoletni użytkownicy[/b]';
echo '[list]';
// $result jest obiektem PDOStatement, ale traktowane jako tablica
// działa tak jakbyśmy zrobili $result = $result->fetchAll();
foreach($result as $row)
{
// Wyświetlamy wyniki z tablicy $row
echo "
[*]{$row['name']} ({$row['age']})";
}
echo '
[/list]';

Wynik tego będzie mniej więcej taki:

Pełnoletni użytkownicy

  • Adam (36)
  • Julian (19)
  • Ania (24)

No dobrze. Skoro już jesteśmy w stanie wybierać dane z bazy czas je stworzyć! Konstrukcja zapytania INSERT czy UPDATE wygląda bardzo podobnie, tylko zamiar $pdo->query() używamy $pdo->exec().
$success = $pdo->exec("INSERT INTO users (name, age) VALUES ('Łukasz', 22)");
if($success)
{
echo 'Łukasz został dodany!';
}
else
{
echo 'Wystąpił błąd.';
}


Bindowanie zapytań

Teraz omówimy jedną z najprzydatniejszych funkcji PDO. Jest to bindowanie zapytań i dzięki temu możemy:
  • Tworzyć zapytania bez zaśmiecania go zmiennymi.
  • Zwiększyć bezpieczeństwo poprzez filtrację danych.
Przeciętne zapytanie do bindowania wygląda mniej więcej tak:
INSERT INTO users (name, surname, age) VALUES (:name, :surname, :age)
Widać tutaj ciągi w stylu :age, które właśnie są wartościami do podstawienia. O ile przy takich zapytaniach nie ma za bardzo różnicy to jeżeli kontaktujemy się z bazą w bardzo zaawansowany sposób to bindownie znacznie zwiększa czytelność kodu. Właściwie to można nawet przekazać konstrukcję zapytań innej osobie, która nie będzie musiała znać nazw zmiennych.

W praktyce bindowanie wygląda tak:
// Tworzymy zapytanie za pomocą $pdo->prepare()
$statement = $pdo->prepare('INSERT INTO users (name, surname, age) VALUES (:name, :surname, :age)');
// Bindowanie
// PDO::PARAM_STR - bindowanie jako ciąg znaków
// PDO::PARAM_INT - bindowanie jako liczba
$statement->bindValue(':name', $_POST['name'], PDO::PARAM_STR);
$statement->bindValue(':surname', $_POST['surname'], PDO::PARAM_STR);
$statement->bindValue(':age', $_POST['age'], PDO::PARAM_INT);
// Wykonujemy zbindowane zapytanie
$success = $statement->execute();

W ten sposób wykonaliśmy prawidłowe zapytanie, które zostało automatycznie zabezpieczone przez PDO i nie musimy się bać, że użytkownik wprowadzi jakieś złe dane ;)

Transakcje

Kolejną z funkcjonalności PDO są tak zwane transakcje. Polega to na tym, że po uruchomieniu transakcji metodą $pdo->beginTransaction() zostaje wyłączony tryb autocommit czyli dane nie są od razu zmieniane w bazie i w każdej chwili (przed ich wysłaniem) można cofnąć całą transakcję za pomocą $pdo->rollBack(). Jest to przydatne gdy w związku z jakąś rzeczą musimy modyfikować kilka tabel i błąd przy wprowadzaniu danych do jednej może rozsypać całą ich strukturę.

Tutaj przedstawię mały przykład z kilkoma powiązanymi zapytaniami i obsługą błędów PDO.
// Rozpoczynamy transakcję
$pdo->beginTransaction();
try
{
$pdo->exec("INSERT INTO users (name, age) VALUES ('Michał', 37)");
$user_id = $pdo->lastInsertId(); // ID wstawionego użytkownika
$pdo->exec("INSERT INTO accounts (money, no, type) VALUES (100, 355515174142, 'normal')");
$account_id = $pdo->lastInsertId(); // ID wstawionego konta
$query = $pdo->prepare("INSERT INTO users_accounts (user_id, account_id) VALUES (:user_id, :account_id)");
$query->bindValue(':user_id', $user_id, PDO::PARAM_INT);
$query->bindValue(':account_id', $account_id, PDO::PARAM_INT);
$query->execute(); // Wykonujemy ostatnie, trzecie zapytanie.
// Jeżeli kod do tej pory nie wyrzucił błędu, czyli działa to
// wykonujemy COMMIT, czyli wstawiamy dane do bazy na zawsze.
$pdo->commit();
}
catch(PDOException $e)
{
// Przy otrzymaniu błędu cofamy wszystkie wprowadzone zmiany
$pdo->rollBack();
}


Mam nadzieję, że ten poradnik pomógł Ci poznać PDO lub chociażby uzupełnić wiedzę o nim. PHP cały czas jest ulepszane i jeżeli chcemy tworzyć nowoczesne skrypty to musimy używać nowoczesnych metod.
Od siebie dodam, że PDO obsługuje bardzo dużo różnych baz a cała zmiana polega na wstawieniu innego tekstu podczas łączenia.

Przydatne linki



#1216 Flask - strony WWW w Pythonie!

Napisane przez Thelleo w 25 sierpień 2012 - 15:49

Flask - strony WWW w Pythonie

Python jest obiektowym i interpretowany językiem. Jest znacznie mniej popularny od np. PHP, ponieważ nie ma w nim żadnych klamr i wydaje się inny od "normalnych" języków programowania, gdyż liczą się w nim wcięcia w kodzie (co może też być utrudnieniem dla ludzi, których kod nie jest zbyt ładny).
Najpopularniejszym frameworkiem od tworzenia stron WWW w tym języku jest Django, jednak bardzo często nie potrzebujemy aż takich kombajnów i dlatego chciałbym zaprezentować wam Flask, który mimo niewielkiego rozmiaru pozwala nam na tworzenie nawet całych portali.

Instalacja

Debian/Ubuntu (Linux)

Aby zainstalować Flaska na systemie Debiano-podobnym należy zalogować się jako root i wykonać następujące komendy.
apt-get install python-pip
pip install Flask
Nie szukaj następnych komend ;) Te dwie wystarczyły i Flask jest już zainstalowany w twoim systemie! Taka jest magia Pythona.

Windows

Nie wykonywałem instalacji na Windowsie a jedynie przepisałem fragment o niej z oficjalnej dokumentacji Flaska, więc w przypadku błędów nie jestem w stanie pomóc.

W Windowsie instalacja jest nieco bardziej skompilowana jednak nie powinna sprawić większego problemu.
Na początku jeżeli jeszcze nie mamy to będziemy zmuszeni pobrać interpreter Pythona ze strony http://python.org/ft...ython-2.7.3.msi.
Następnie gdy go już zainstalujemy będziemy musieli pobrać ten plik: http://python-distri...ribute_setup.py i wrzucić go do katalogu Scripts w naszym folderze z Pythonem. Np. C:\Python27\Scripts\
Gdy to już zrobimy będziemy musieli uruchomić skrypt. Można to zrobić dwuklikiem jednak jeżeli Python nie zintegrował się z plikami .py to można to wykonać komendą:
C:\Python27\python.exe C:\Python27\Scripts\distribute_setup.py
Po wykonaniu skrypt powinien nam pobrać archiwum, w którym powinien znajdować się folder. Zawartość tego folderu wypakowujemy do katalogu Scripts w folderze Pythona i wykonujemy komendę:
C:\Python27\python.exe C:\Python27\Scripts\easy_install.py pip
A następnie kolejną:
C:\Python27\Scripts\pip.exe install Flask

Pierwsza strona

Gdy już uporamy się z instalacją będziemy mogli tworzyć własne strony. Żeby to zrobić należy stworzyć plik z rozszerzeniem .py np. testujemyPythona.py.
W tym pliku możemy wrzucić następującą treść:
from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Testujemy!"

if __name__ == "__main__":
    app.run(host=0.0.0.0,port=6666)
Po zapisaniu uruchamiamy go komendą
python testujemyPythona.py
Lub dwuklikiem jeżeli używamy Windowsa. Powinniśmy otrzymać teraz tekst w stylu:

* Running on http://0.0.0.0:6666/
Aby sprawdzić czy rzeczywiście sie nam udało musimy wejść na adres http://localhost:6666 lub http://ip.lub.domena.serwera.pl:6666.
Powinniśmy otrzymać tekst Testujemy, jeżeli tak się stało to brawo! Nasz Flask działa jak powinien.

A teraz omówimy sobie kod który napisaliśmy:
from flask import Flask # Importujemy paczkę z Flaskiem
app = Flask(__name__) # Tworzymy nowy obiekt z klasy Flask(plik). __name__ zawiera nazwę aktualnego pliku.

# Tworzymy funkcję, która wywoła się gdy tzw. route czy ścieżka
# wyszukiwana przez użytkownika zgadza się z tym co podaliśmy w
# parametrze @app.route(). Funkcja może mieć dowolną nazwę i musi
# zwracać treść, która zostanie wyświetlona użytkownikowi.
@app.route("/")
def hello():
    return "Testujemy!"

# Teraz jeżeli aktualny plik jest plikiem który uruchomiliśmy to
# startujemy serwer. Można zmodyfikować jego port oraz host
# Domyślny port serwerów HTTP to 80
if __name__ == "__main__":
    app.run(host=0.0.0.0,port=6666)

Pierwsza prawdziwa strona - wizytówka!

Teraz do naszego folderu z plikiem testujemyPythona.py dodajemy katalog templates w którym schowamy plik html, które zostaną wyrenderowane przez Flaska jako szablony.

Na początku stworzymy sobie plik templates/szablon.html z treścią:
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>{{ title }} - Wizytówka</title>
</head>
<body>
    <h1>Wizytówka</h1>
    <p>
        {{ content }}
    </p>
</body>
</html>
Zauważalną rzeczą są dwie wartości ukryte między znakami {{ wartośc }}. Są to parametry, które przekażemy do naszego szablonu za pomocą Flaska.

Stworzymy sobie jeszcze plik templates/home.html z treścią:
Witaj na mojej wizytówce! Stworzyłem tą stronę w 2009 roku a teraz mamy {{ year }}!
[url="/omnie"]Poczytaj coś na mój temat![/url]
Oraz templates/about.html z treścią:
Nazywam się Thelleo!
No dobrze. Teraz gdy nasze widoki są już skończone zrobimy sobie prostą aplikację, która je prawidłowo wyświetli. W tym celu edytujemy plik testujemyPythona.py i piszemy w nim coś takiego:
import datetime # Dolaczamy funkcje zwiazane z data
from flask import Flask
app = Flask(__name__)

@app.route("/")
def home():
    now = datetime.datetime.now()
    # Tworzymy szablon z aktualna strona i przypisujemy
    # jej zmienna zawierajaca rok
    page = render_template('home.html', year=now.year)
    # Zwracamy szablon z przyspisana trescia pochodzaca
    # z szablonu powyzej i tytulem
    return render_template('szablon.html', title="Home", content=page)
@app.route("/omnie")
def about():
    # Robimy tak jak powyzej, jednak teraz bez przypisywania
    # roku do pierwszego szablonu
    page = render_template('about.html')
    return render_template('szablon.html', title="O mnie", content=page)

if __name__ == "__main__":
    app.run(host=0.0.0.0,port=6666)

Teraz gdy odpalimy skrypt na stronie głównej powinien być aktualny rok oraz link do strony "O mnie", na której powinien się pokazać tekst "Jestem Thelleo". W poradniku użyłem dość dużo kodu a tak naprawdę mało wyjaśnień, jednak osobiście uważam, że opisane przykłady są lepsze od analizowania każdej linijki osobno.
Jeżeli ktoś miałby jakieś pytania, wątpliwości lub problemy to śmiało pytać ;) Ja nie gryzę, przynajmniej nie od razu.

Przydatne linki



#932 [PHP] Klasy i metody magiczne

Napisane przez Thelleo w 20 sierpień 2012 - 22:04

1. PHP - Klasy i metody magiczne
Programowanie obiektowe w PHP nie jest takie złe jak dużej ilości ludzi się wydaje. Co prawda do obiektowości z np. Javy mu dużo brakuje, ale posiada bardzo ciekawą funkcjonalność zwaną metodami magiczntymi. Są to funkcje, które po wykryciu ich w klasie wykonują się gdy PHP uzna, że powinny.

2. Przykład
Jedną z metod magicznych jest __toString, wywoływana gdy klasa jest w sytuacji w której powinna zostać zamieniona na ciąg znaków, np. podczas próby jej wyświetlenia.

class Klasa
{
public $text;

public function __toString()
{
return $this->text; // Metoda magiczna __toString zwraca zmienną $this->text
}
}
$obiekt = new Klasa;
$obiekt->text = 'Jestem bardzo fajnym tekstem';
echo $obiekt; // Klasa jest traktowana jako ciąg znaków i PHP wykonuje metodę __toString, która wyświetla zmienna $obiekt->text


Jak wdać metody magiczne definiujemy jak każdą inną metodę, a jedyną różnicą jest fakt, że są one poprzedzone podwójnym znakiem _.
Nie powinniśmy też definiować metod z taką samą strukturą nazwy, bo w przyszłości być może developerzy wprowadzą kolejną metodę magiczną i nasz kod pójdzie się je... zacznie wyświetlać błędy ;)
A wracając do samej __toString to być może wciąż niektórzy zastanawiają się po co jej używać skoro i tak można to zrobić zwykłą funkcją. Oczywiście, że można, ale metody magiczne powodują, że kod czasami jest znacznie lepszy. Najlepsze zastosowanie jest w momencie gdy klasa operuje na jednym fragmencie tekstu i od niego zależą inne metody. Dla przykładu weźmy chociażby klasę pozwalającą nam obrabiać tekst. Podczas jej tworzenia podajemy nasz tekst, operujemy na metodach klasy a gdy chcemy wyświetlić nasz przeformatowany tekst to zamiast np. echo $obiekt->get() wpisujemy echo $obiekt

3. Spis wszystkich metod magicznych i omówienie ich działania
  • __call($method, $arguments)
    Metoda jest wywoływana gdy odwołamy się do jakiejkolwiek innej metody w klasie. Parametr $method zawiera nazwę metody, a $arguments jest tablicą z argumentami jakich użyliśmy do wywołania funkcji.
  • __callStatic($method, $arguments)
    Metoda działa tak samo jak powyżej, tylko, że ona nasłuchuje jedynie na wywołania statycznych metod oraz jest dostępna dopiero od PHP 5.3
  • __get($name)
    Metoda jest wywoływana gdy próbujemy się odwołać do nieistniejącej zmiennej w klasie w stylu $obiekt->jakas_nieistniejaca_zmienna. W argumencie $name znajduje się nazwa zmiennej, więc tą metodę można wykorzystać do klas będących pojemnikami na treść.
  • __set($name, $value)
    Metoda jest wywoływana gdy próbujemy przypisać wartość do nieistniejącej zmiennej w stylu $obiekt->jakas_nieistniejaca_zmienna = 'wartość'. Argument $name posiada nazwę zmiennej, a argument $value wartość, którą chcemy jej przypisać. Takie coś podobnie jak __get() można wykorzystać do klas będących pojemnikami.
  • __isset($name)
    Jest wywoływana gry próbujemy odwołać się do zmiennej w klasie za pomocą funkcji isset() lub empty(). Parametr $name zawiera nazwę zmiennej.
  • __unset($name)
    Jest wywoływana gry próbujemy odwołać się do zmiennej w klasie za pomocą funkcji unset(). Parametr $name zawiera nazwę zmiennej. Można to wykorzystać, aby np. nie pozwolić na usunięcie jakiejś ważnej publicznej zmiennej.
  • __sleep()
    Jest wywoływana gdy serializujemy jakiś obiekt za pomocą funkcji serialize(). Powinna zwracać tablicę z danymi.
  • __wakeup()
    Działa tak jak powyższa, tylko reaguje na deserializacje za pomocą funkcji unserialize()
  • __invoke([dowolne parametry])
    To bardzo ciekawa metoda więc warto się nią zainteresować. Otóż pozwala na odwołanie się do obiektu jak do zwykłej funkcji! Wtedy parametry są przekazywane jako parametry metody __invoke().
    Przykład:
    class Dodawator
    {
    public function __invoke($a, $B)
    {
    return $a + $b;
    }
    }
    $klasa = new Dodawator;
    echo $klasa(23, 7); // Wyswietli 30, bo wywoła metodę __invoke()
  • __clone()
    Metoda wykonuje się gdy próbujemy skopiować klasę operatorem $klasa = clone $stara_klasa;

4. Przydatne linki