Өөрийн фраймворкоо Symfony2 -ын компонент дээр үүсгэе (хэсэг 2)

Чимэг: Энэхүү нийтлэл нь “Өөрийн фраймворкоо Symfony2 -ын компонент дээр үүсгэе” цувралын нэг хэсэг юм.

Код руугаа шумбан орж шинэчлэл сайжруулалт хийхээсээ өмнө та бид яагаад фраймворк ашиглах нь энгийн PHP аппликэйшнийг байгаа чигээр нь ашиглахаас илүүд үзэх болснийг иргэн харахыг хүслээ. Хэдийгээр маш жижиг хэмжээний байсан ч фрэймворк ашиглах нь үнэндээ сайхан санаа ба яагаад та өөрийн фрэймворкоо Symfony2-ын компонентууд дээр үүсгэж байгаа нь ч гэсэн юучгүй тэгээс нь эхлээс л дээр юм.

Чимэг: Би илэрхий зүйл болох фрэймворкийг олон хөгжүүлэгчтэй том хэмжээний прожект дээр  ашиглах нь яагаад давуу талтай байдаг талаар энд ярихгүй ба Интернетэд үүний талаар хангалттай мэдээлэл бий.

Хэдийгээр бидний өчигдрийн бичсэн аппликэйшн маш энгийн хялбар боловч, үүнд бас хэд хэдэн асуудал байнаа:

<?php

// framework/index.php

$input = $_GET[‘name’];

printf(‘Hello %s’, $input);

Нэгдүгээрт, хэрэв URL хүсэлтийн утгад name хувьсагчийн утга өгөгдөөгүй бол та PHP анхааруулгыг дэлгэцийн дээр байнга харах болно; Тиймээс алив үүнийг засцгааъя:
<?php

// framework/index.php

$input = isset($_GET[‘name’]) ? $_GET[‘name’] : ‘World’;

printf(‘Hello %s’, $input);

Мөн энэ аппликэйшн одоогоор ямар ч хамгаалалт байхгүй. Итгэж байна уу?  Энэ энгийн жижиг PHP код ч гэсэн Интернетийн хамгийн түгээмэл хамгаалалтын асуудал болох XSS(Cross-Site Scripting) -ын халдалтад хялбархан өртөнө.  Доорх код одоо илүү хамгаалттай болсон хувилбар:
<?php

$input = isset($_GET[‘name’]) ? $_GET[‘name’] : ‘World’;

header(‘Content-Type: text/html; charset=utf-8’);

printf(‘Hello %s’, htmlspecialchars($input, ENT_QUOTES, ‘UTF-8’));

Чимэг:
Магадгүй та ажигласан байх, htmlspecialchars -аар кодоо хамгаалж өгөх нь ихэвчлэн урт, бичлэг ихтэй, байнга санаад байхааргүй зүйл. Энэ бол нэг шалтгаан болох яагаад тэмплэйтийн хөдөлгүүр Twig -ыг ашиглахын давуу тал юм. Twig-т алгасаж унших (escaping) нь автоматаар идэвжсэн байдаг (мөн е шүүлтүүрийн хэрэглээ ч гэсэн мөн бага ажиллагаатай).

 

Бид PHP анхааруулга, сануулгаас зайлсхийж, кодоо илүү хамгаалттай болгохгүй л бол хэдийгээр бид маш жижигхэн хэмжээний код бичсэн нь тийм ч хялбар эд биш болохыг та анзаарсан байх.

Хамгаалалтгүй байлаа ч энэ код энгийн тестлэхэд хүртэл төвөгтэй. Хэдийгээр тест бичээд байх тийм их зүйлгүй ч гэлээ, хамгийн энгийн PHP кодын нэгжийн тестэд (unit test) хүртэл асуудалтай, төвөгтэй сэтгэгдэл төрүүлж байна.
Дээрх кодонд дараах байдлаар тийм ч сайнгүй PHPUnit нэгжийн тест бичлээ.

<?php

// framework/test.php

class IndexTest extends \PHPUnit_Framework_TestCase
{
public function testHello()
{
$_GET[‘name’] = ‘Fabien’;

 ob_start();
include ‘index.php’;
$content = ob_get_clean();

$this->assertEquals(‘Hello Fabien’, $content);
}
}

Чимэг:
Хэрэв бидний аппликэйшн бага зэрэг том байсан бол бид илүү олон асуудалтай тулгарах байсан байх. Хэрэв та илүү ихийг сонирхож байвал, Symfony2 Энгийн PHP-ын эсрэг бүлгийг уншихыг санал болгож байна.

Яг энд хүрээд та хуучин аргаар код бичихийн оронд фраймворк (ямар ч хамаагүй фрэймворк) ашиглах нь маш 2 том шалтгаан болох хамгаалалт болон тестлэх хоёрыг олж харахгүй байгаа бол та үргэлжлүүлж ушихгүйгээр өмнө нь хийж байсан ямар ч хамаагүй код болох тэрэндээ буцаад очиж болно.

Чимэг:
Фрэймворк ашиглах нь мэдээж  таньд дан ганц хамгаалалт болон тест бичихээс илүү ихийг өгөх ёстой, гэвч нэг анхаарах зүйл гэвэл сонгож байгаа фраймворк тань таныг илүү сайн, хурдан код бичихэд тусладаг байх ёстой.

HttpFoundation Компоненттэй цуг ОХП (Объект Хандалтад Програмчлал) руу

Вэб код бичих гэдэг нь HTTP холбогдож, ажиллах юм. Тиймээс бидний фрэймворкийн үндэс суурь нь  HTTP specification (тодорхойлолт) – уудыг гол зарчимаа болгосон байх хэрэгтэй.

HTTP -ын тодорхойлолтууд нь хэрэглэгч (тухайлбал вэб хөтөч) сервертэй (вэб сервэр дээр байгаа бидний аппликэйшнтай) хэрхэн  холбогдон ажиллахыг тодорхойлж өгдөг. Хэрэглэгч болон серверийн хоорондын харилцаа нь маш сайн тодорхойлогдсон зурвас (мессеж) -ээр тодорхойлогдсон хүсэлт болон хариултаас тогтдог:  хэрэглэгч сервер рүү хүсэлт явуулдаг ба тухайн хүсэлтэнд тулгуурлаж, сервер хариу буцаадаг.

PHP-д хүсэлт нь глобал хувьсагчуудаар ($_GET, $_POST, $_FILE, $_COOKIE,$_SESSION…) төлөөлөгддөг ба хариулт нь (echo, header, setcookie, …) функцуудаар боловсруулагддаг.

Илүү сайн код бичихийн эхний алхам нь магадгүй Объект-Хандалтад аргыг хэрэглэх нь байх; энд л  Symfony2 HttpFoundation компонентын гол зорилго оршиж байгаа юм.  Тодорхойлбол: PHP-ын өгөгдмөл (default) глобал хувьсагчуудыг орлуулж, Объект-Хандалтад давхаргаар функцжуулах юм.

Энэ компонентоо ашиглахын тулд composer.json файлаа нээгээд үүнийгээ нэг хамаарал сангаар (dependency) прожектдоо нэмж өгнө:

# framework/composer.json
{
"require": {
"symfony/class-loader": "2.1.*",
"symfony/http-foundation": "2.1.*"
}
}

Тэгээд, update командыг ажиллуулна.

$ php composer.phar update

Эцэст нь, компонентыг дуудахад хэрэгтэй кодоо autoload.php файлын төгсгөлд нэмж өгнө:

<?php

// framework/autoload.php

$loader->registerNamespace(‘Symfony\\Component\\HttpFoundation’, __DIR__.’/vendor/symfony/http-foundation’);

Одоо цөмөөрөө аппликэйшнаа Хүсэлт (Request) болон Хариулт (Response) классуудыг ашиглан дахин бичицгээе:

<php

// framework/index.php

require_once __DIR__.’/autoload.php’;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

$request = Request::createFromGlobals();

$input = $request->get(‘name’, ‘World’);

$response = new Response(sprintf(‘Hello %s’, htmlspecialchars($input, ENT_QUOTES, ‘UTF-8’)));

$response->send();

createFromGlobals() функц (method) тухайн PHP глобал хувьсагчууд дээр тулгуурлан Request объектыг үүсгэдэг.

send() функц нь Response объектыг хэрэглэгч рүү буцааж илгээнэ (эхлээд HTTP толгой хэсгийг, араас нь агуулгыг (content)-г гаргадаг).

Санамж: ; send() дуудагдахаас өмнө, бид өөрсдийн буцааж буй Хариулт (Response) HTTP -ын шаардлагуудтай таарч, тохирч байгааг баталгаажуулах зорилгоор prepare() ($response->prepare($request);) функцыг нэмж дуудаж өгөх хэрэгтэй. Тухайлбал: Хэрэв хуудас HEAD method-оор дуудагдвал, Хариулт (Response) -ын агуулга нь устгагдсан байх болно.

Өмнөх кодоос ялгагдах гол ялгаа нь таньд одоо HTTP зурвасуудыг бүрэн удирдах эрх нь байгаа. Та өөрийн хүссэн хүсэлтээ үүсгэж, өөрийн тааллаар хариу буцаах боломжтой болсон.

Чимэг: Бид дахин бичигдсэн кодондоо Response объектынхоо Content-Type толгой хэсгийн charset-ыг UTF-8 өгөгдмөлөөр зааж өгөөгүй байгаа.

Request класын ачаар та хүсэлтийн бүх мэдээллийг хурууны үзүүр дор хялбархан харах боломжтой.

<?php

// хүсэлт дэхь URI (e.g. /about) -ыг query параметеруудыг хассан хэлбэрээр
$request->getPathInfo();

// GET болон POST хувьсагчууд
$request->query->get(‘foo’);
$request->request->get(‘bar’, ‘default value if bar does not exist’);

// SERVER хувьсагчуудыг харуулна
$request->server->get(‘HTTP_HOST’);

// foo гэсэн UploadedFile-ын утгыг авна
$request->files->get(‘foo’);

// COOKIE-ын утгыг авна
$request->cookies->get(‘PHPSESSID’);

// HTTP хүсэлтийн толгой утгыг нормалчлагдсан, жижиг үсгээр авна
$request->headers->get(‘host’);
$request->headers->get(‘content_type’);

$request->getMethod();    // GET, POST, PUT, DELETE, HEAD
$request->getLanguages(); // хэрэглэгчийн авч болох хэлнүүдийн array-ууд

Та мөн хүсэлтийг үүсгэж болно:

$request = Request::create('/index.php?name=Fabien');

Response классаар та мөн хариуг хялбархан засчиж болно:

<?php

$response = new Response();

$response->setContent(‘Hello world!’);
$response->setStatusCode(200);
$response->headers->set(‘Content-Type’, ‘text/html’);

// configure the HTTP cache headers
$response->setMaxAge(10);
Санамж: Response-ын алдааг харахын тулд string рүү хөрвүүл; Энэ нь хариултын HTTP төлөөлөлийг буцаана (толгой болон агуулга).

Эдгээр классууд нь бусад Symfony дахь кодуудын адилаар,  хамгаалалтуудын асуудлуудаа бие даасан мэргэжлийн байгууллагаар шалгуулж, аудит хийгүүлсэн болно. Нээлттэй эхийн төсөл байх гэдгийн бас нэг утга нь дэлхийн маш олон хөгжүүлэгчид кодыг уншаад, боломжит асуудлуудыг аль хэдийн шийдцэн байдагт байгаа юм. Та хамгийн сүүлд хэзээ өөрийн үүсгэсэн фрэймворкоо гадны нууцлалын байгуулалгаар шалгуулахаар хүсэлт гаргаж байсан бэ?

Хэдийгээр хамгийн хялбар байж болох хэрэглэгчийн IP авах нь хүртэл эргэлзээтэй байж болно:

<?php

if ($myIp == $_SERVER[‘REMOTE_ADDR’]) {
// хэрэглэгчийг мэдлээ, илүү эрхийг түүнд өгье
}

Дээрх код таныг ажиллагаатай сервер дээрээ тонгоруулсан (reverse) proxy нэмэх хүртэл хэвийн ажиллана. Харин одоо буюу тонгоруулсан proxy-той үед, та хөгжүүлэлтийн машин (proxy байхгүй) болон сервер хоёуланд нь ажиллаж болохоор кодоо шинэчлэх шаардлагатай болж байна:

<?php

if ($myIp == $_SERVER[‘HTTP_X_FORWARDED_FOR’] || $myIp == $_SERVER[‘REMOTE_ADDR’]) {
// хэрэглэгчийг мэдлээ, илүү эрхийг түүнд өгье
}

Request::getClientIp() методыг ашиглах нь таньд дээрх асуудлыг шийдсэн тохиромжтой үр дүнг өгнө (мөн гинжин холбогдсон proxy-уудыг мөн агуулсан).

<?php

$request = Request::createFromGlobals();

if ($myIp == $request->getClientIp()) {
// хэрэглэгчийг мэдлээ, илүү эрхийг түүнд өгье
}

Мөн хамгаалалт нь давхар өгөгдсөнөөрөө давуу талтай. Хамгаалалттай гэсэн нь ямар утгыг агуулж байгаа вэ?
$_SERVER[‘HTTP_X_FORWARDED_FOR’] утгыг ямар нэгэн proxy-гүй үед эцсийн хэрэглэгчээс ирсэн байдлаар авах нь найдваргүй. Тиймээс энэ кодоо ажиллаж буй (production) сервер дээр proxy-гүйгээр ашиглавал, таны систем маш хялбархан энгийн дайралтанд өртөнө. Тиймээс та энэ толгой хэсгийн мэдээлэлд итгэхийн тулд trustProxyData() методыг дуудаж, ажиллуулах ёстой:

<?php

Request::trustProxyData();

if ($myIp == $request->getClientIp(true)) {
// хэрэглэгчийг мэдлээ, илүү эрхийг түүнд өгье
}

Одоо getClientIp() метод ямар ч нөхцөлд найдвартайгаар ажиллана. Та одоо үүнийг өөрийн ямар ч прожектдоо авч ашиглахад боломжтой ба код үнэн зөв, найдвартайгаар ажиллах болно. Энэ бол фрэймворк ашиглахын нэг давуу тал юм. Хэрэв та фрэймворкыг эхнээс нь бичвэл, та энэ бүх асуудлыг бодож үзэх хэрэгтэй болно. Яагаад аль хэдийн ажиллаж байгаа технологийг ашиглаж болохгүй гэж?

Санамж: Та HttpFoundation компонентын талаар илүү ихийг мэдхийг хүсвэл, API -ыг эсвэл Symfony вэб сайт дээрх тухайлан зориулагдсан документыг унших боломжтой.

Итгэнүү байнуу хамаагүй, одоо  бид өөрсдийн анхны фраймворктой боллоо. Хэрэв та хүсвэл энд хүрээд зогсож, больж болно. Зөвхөн Symfony2 HttpFoundation компонентыг дангаар нь ашиглаад  та илүү сайн, илүү тестлэж болохуйц код бичих боломжыг энэ компонент таньд олгодог.  Мөн энэ компонент өдөр бүр тохиолдох асуудлыг тань аль хэдийн шийдээд өгцөн учираас, таныг кодоо илүү хурдан бичих боломжыг бас олгодог.

Зарим нэг баримтыг дурьдвал, Drupal (шинээр хийгдэж буй хувилбар 8) шиг прожектууд HttpFoundation компонент-ыг ашиглаж байгаа. Хэрэв энэ тэдгээрт ажиллаж байгаа бол, таны прожект-д ч мөн ажиллах байх. Дугуйг дахин бүү зохио!

Нэг хэлэх гээд бараг мартсан давуу тал гэвэл: HttpFoundation компонентыг ашиглах нь үүнийг ашиглаж буй фрэймворкууд болон апплэйшнуудад өөр хоорондын бие биетэйгээ ажиллах ажиллагаа, уялдааг нэмэгдүүлдэг. Өнөөдрийн байдлаар Symfony2, Drupal 8, phpBB 4, Silex, Midgard CMS, Zikula … гэх мэт прожектууд энэ компонентыг ашиглаж байна.

Эх сурвалж: http://fabien.potencier.org/article/51/create-your-own-framework-on-top-of-the-symfony2-components-part-2

Advertisements

3 thoughts on “Өөрийн фраймворкоо Symfony2 -ын компонент дээр үүсгэе (хэсэг 2)

    • Одоогоор шинээр хичээл оруулах зав болохгүй байнаа. Удахгүй нэг ажлын ард гарсны дараа нилээн идэвхтэй шинэ зүйлүүд оруулах төлөвлөгөөтэй байгаа. 1 сарын дундаас л болох болов уу,
      Ямартай ч хүсэлтээ илгээсэнд баярлалаа. Ямар зүйлийн талаар илүү сонирхож байгаагаа илгээвэл бас зүгээр шүү.

      Амжилт!

Хариулт үлдээх

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Өөрчлөх )

Twitter picture

You are commenting using your Twitter account. Log Out / Өөрчлөх )

Facebook photo

You are commenting using your Facebook account. Log Out / Өөрчлөх )

Google+ photo

You are commenting using your Google+ account. Log Out / Өөрчлөх )

Connecting to %s