[PHP 0 to 1] : Cơ bản về Web

Mục tiêu : Nhằm hiểu ở mức nền tảng, cơ bản Web là gì và hoạt động ra sao

Web là gì ?

Website (viết tắt là Web) là một tập hợp những trang mạng, bao gồm thông tin và nội dung số, thường được định danh bằng một tên miền và được xuất bản trên ít nhất một máy chủ mạng. Một Web có thể truy cập qua mạng với giao thức IP, thường là mạng Internet qua một đường dẫn định vị tài nguyên (URL = Uniform Resource Locator).

Mục đích của Web là để đăng tải, chia sẻ, giao dịch và xử lý thông tin số thông qua mạng máy tính.

URL là địa chỉ được gọi là định danh của một tài nguyên cụ thể trên mạng Internet, thông thường URL khác nhau sẽ cho ra một tài nguyên khác nhau. Một URL thông thường có dạng như sau:

1
<protocol>://<host><:port>/<path/to/resource><?query>

Trong đó:

  • : giao thức, ở đây thường là http hoặc https
  • : địa chỉ host nơi chứa tài nguyên, thường là IP hoặc tên miền (Domain name)
  • <path/to/resource> : đường dẫn tìm tới tài nguyên chứa trong host
  • <?query> : các đối số kèm theo cung cấp thêm thông tin cho server để trả về kết quả phù hợp hơn, bắt đầu bằng dấu ?, mỗi cặp giá trị key=value cách nhau bằng dấu &. Ví dụ như : ?page=1&limit=100&from_year=2018

Internet hoạt động thế nào ? (Internet Protocol)

Mạng internet là mạng giữa các máy tính được kết nối với nhau trực tiếp hay gián tiếp thông qua các điểm trung chuyển khác nhau tạo thành một mạng lưới kết nối rộng lớn. Mỗi máy trực tiếp tham gia vào mạng sẽ được cấp một địa chỉ IP (địa chỉ IPv4 có dạng A.B.C.D với A,B,C,D từ 0-255) duy nhất trong hệ thống mạng. Vì vậy việc gửi dữ liệu từ máy A sáng máy B là việc gửi từ địa chỉ IP của máy A sang địa chỉ IP của máy B. Do các dữ liệu được trung chuyển qua các điểm máy trung gian trong mạng máy tính vì không có đường hướng cụ thể, công đoạn này gọi là Routing. Dữ liệu sẽ được gửi dưới dạng các gói tin từ IP A sang IP B qua hệ thống Routing toàn cầu.

Do việc trung chuyển gói tin qua nhiều điểm mới tới đích, vì thế việc đảm bảo gói tin được toàn vẹn 100% là điều không thể (mà chỉ đảm bảo ở mức nỗ lực cố gắng cao nhất có thể). Vì thế dễ dẫn đến tình trạng gói tin bị mất mát, chỉnh sửa, trùng lặp và sai thứ tự trong quá trình trung chuyển trong mạng máy tính. Vì vậy mà các ứng dụng mạng muốn đảm bảo tính chính xác toàn vẹn dữ liệu được xây dựng trên một lớp Protocol bên trên bao gồm các cơ chế và quy tắc để đạt được tính toàn vẹn này, điển hình là giao thức TCP (Transmission Control Protocol).

HTTP Protocol

HTTP Protocol (HyperText Transfer Protocol) là giao thức truyền tải siêu văn bản (nghe có vẻ vi diệu), nó được xây dựng trên nền tảng giao thức TCP để đảm bảo tính toàn vẹn của dữ liệu giữa 2 máy (thường gọi là máy chủ Server và máy khách Client).

Request

Đầu tiên Client sẽ kết nối tới Server thông qua một cổng nhất định do máy chủ cung cấp dịch vụ HTTP (thường là cổng 80). Sau khi kết nối thành công, Client sẽ chuyển tiếp yêu cầu về dữ liệu (Request) mà nó muốn gửi lên cho Server xử lý. Request đó sẽ bao gồm 2 phần là đầu (HTTP Headers) và thân (HTTP Body).

Ví dụ như sau :

1
2
3
4
5
6
POST /du-lieu HTTP/1.1
Host: example.com
User-Agent: curl/7.54.0
Accept: */*

username=admin&password=secret

Bên trên là một HTTP Request bao gồm 2 phần :

  • Phần Header bao gồm 4 dòng đầu, dòng đầu tiên đặc biệt theo nguyên tắc là [METHOD] [URL] HTTP/[HTTP_VERSION], cung cấp cho ta biết phương thức gửi là gì (POST), điểm cuối chứa dữ liệu (/du-lieu) và phiên bản HTTP (1.1). Các dòng tiếp theo của Header theo nguyên tắc là KEY: VALUE nhằm cung cấp thông tin thêm cho Server hiểu chính xác Client đang cần gì, muốn gì và chấp nhận định dạng trả về như thế nào.
  • Phần Body dòng thứ 6 trở xuống, dòng thứ 5 là dòng trắng để ngăn cách Header và Body. Phần này chứa những thông tin dữ liệu kèm theo đầy đủ của Request.

Response

Sau khi nhận được Request từ Client, Server sẽ xử lý tính toán và trả về cho Client một trả lời (Response). Response này cũng bao gồm 2 phần như Request là Header và Body

Ví dụ như sau :

1
2
3
4
5
6
7
8
9
10
11
HTTP/1.1 200 (OK)
Server: nginx
Date: Wed, 31 Oct 2018 08:07:09 GMT
Content-Type: text/plain; charset=utf-8;
Content-Length: 11
Connection: keep-alive
Access-Control-Allow-Origin: *
Cache-Control: max-age=300

hello
world
  • Phần Header bao gồm 8 dòng đầu, dòng đầu tiên đặc biệt theo nguyên tắc là HTTP/[HTTP_VERSION] [STATUS CODE] [STATUS TEXT], cung cấp cho ta biết phiên bản HTTP (1.1), trạng thái của response qua 3 con số được quy định theo chuẩn RFC 7231 và chú thích cho trạng thái. Các dòng tiếp theo của Header theo nguyên tắc là KEY: VALUE nhằm cung cấp thông tin thêm cho Client hiểu chính xác Server trả về định dạng gì, độ dài bao nhiêu và một số quy tắc khác.
  • Phần Body dòng thứ 10 trở xuống, dòng thứ 9 là dòng trắng để ngăn cách Header và Body. Phần này chứ những thông tin dữ liệu kèm theo đầy đủ của Response.

Hosting, Domain, DNS, Database, HTTPS

Hosting

Hosting là nơi chứa dữ liệu, mã nguồn của trang web. Hosting sẽ nằm trên Server vật lý, và Server này sẽ chia sẻ tài nguyên bao gồm CPU, bộ nhớ và đĩa cứng để phục vụ cho vận hành Website. Có thể xem Hosting là một miếng đất để xây dựng một cái khung nhà (Source Code) trên mảnh đất đó.

Tên miền (Domain Name) và DNS

Như các bạn đã biết Client và Server nói chuyện với nhau qua một kết nối giữa IP của Client và IP của Server. Đồng nghĩa là nếu Client không có, không nhớ địa chỉ IP của Server thì coi như không thể thiết lập kết nối. Do đó người ta đã lập trên một cách dễ nhớ hơn là tạo nên một cuốn sổ danh bạ địa chỉ IP, cơ chế tạo nên cuốn sổ danh bạ này gọi là DNS (Domain Name Resolvers) hay còn gọi là quá trình phân giải tên miền thành địa chỉ IP.

Khi bạn truy cập vào một tên miền dễ nhớ như abc.com, thì lập tức Client sẽ dùng một dịch vụ phân giải DNS của các nhà mạng để tra trong cuốn danh bạ rằng abc.com là địa chỉ IP nào. Sau khi có được địa chỉ IP này, Client sẽ thiết lập kết nối tới địa chỉ IP đó. Nếu không tìm ra địa chỉ IP, Client sẽ báo ra một lỗi là “Thất bại trong quá trình phân giải DNS hoặc tên miền này không tồn tại”.

Ngoài tính năng là tạo sự dễ nhớ, domain còn giúp cho một Server chạy được rất nhiều trang web với domain khác nhau chỉ với 1 địa chỉ IP. Lúc này Web Server sẽ phân biệt domain nào cho dữ liệu nào dựa vào HTTP Header Host: abc.com mà Client gửi lên lúc tạo Request. Như thế, số lượng trang web với domain khác nhau sẽ không bị phụ thuộc vào số địa chỉ IP (tối đa là 255^4 địa chỉ IPv4 , về địa chỉ IPv6 bạn có thể tìm hiểm thêm trên Google).

Database

Database (cơ sở dữ liệu), cái tên này sẽ làm nhiều người lầm tưởng hay mặc định là những phần mềm database lớn như MSSQL, MySQL hay Oracle với hàng triệu dòng mới gọi là database. Nhưng định nghĩa của Database đơn giản chỉ là một nơi có khả năng lưu trữ, hỗ trợ thao tác đọc và ghi dữ liệu vào bộ nhớ lưu trữ. Ví dụ như một file text đơn giản, một file csv, một file excel, một file sqlite, một server MySQL hoặc một server Key-Value đều được gọi là database.

Tuỳ theo nhu cầu mà người phát triển sẽ lựa chọn cho mình một database phù hợp chứ không có một database nào là bá đạo hạt gạo, xịn nhất cả.

HTTPS

Dạo gần đây, khái niệm này mới thật sự nổi lên như một làn sóng về bảo mật thông tin cá nhân. HTTP(S) với chứ S là Secure nghĩa là bảo mật, an toàn hơn.

Như các bạn cũng đã thấy ở phần trên về HTTP, mọi dữ liệu kể cả Request lẫn Response đều được truyền giữa Client và Server dưới dạng là plain text (chữ thường) không được mã hoá. Vì thế nảy sinh ra rủi ro dữ liệu sẽ bị nghe lén, đánh cắp hoặc thậm chí là sửa đổi trên đường trung chuyển qua các nốt trung gian trong hệ thống mạng mà Client và cả Server không hề hay biết.

HTTPS sử dụng công nghệ bảo mật là SSL (hoặc mới nhất là TLS) để mã hoá và chứng thực kết nối giữa Client và Server là an toàn và bảo mật. Về cơ chế làm việc của HTTPS nói riêng là TLS nói chung mình sẽ nói sâu hơn trong một chuyên đề nâng cao về bảo mật.

Request and Response Life Cycle (vòng đời Request và Response)

Bên dưới là hình phác hoạ một vòng đời thông thường của một HTTP Request từ lúc Client gửi yêu cầu tới lúc nhận được HTTP Response, bao gồm 7 bước :

  1. Tra cứu dịch vụ DNS xem IP của tên miền abc.com là gì ?
  2. Dịch vụ tìm thấy IP là 1.2.3.4
  3. Client mở kết nối giao thức HTTP tới server có IP 1.2.3.4
  4. HTTP Web Server ở server nhận được HTTP Request, liền trung chuyển cho mã nguồn website xử lý
  5. Tính toán, xử lý dựa trên HTTP Request có được
    1. Kết nối với Database (nếu cần), rồi truy vấn (query) những dữ liệu cần thiết để hiện thị, tính toán.
    2. Database trả về kết quả cho mã nguồn website dữ liệu để tiếp tục tính toán, xử lý
  6. Sau khi mã nguồn tính toán xong nó sẽ trả về một HTTP Response cho HTTP Web Server
  7. Nhận được HTTP Response từ mã nguồn, HTTP Web Server trung chuyển về cho Client để hiển thị kết quả.

http-request-response-life-cycle

[Series mới] : Học lập trình Web bằng PHP và MySQL

Giới thiệu

Xin chào các bạn, sắp tới mình sẽ cố gắng viết về một chuyên đề mới đó là “Học lập trình Web bằng PHP và MySQL” từ cơ bản đến nâng cao (cơ bản là ở mức chưa biết gì về lập trình web, nâng cao là ở mức bạn có thể xin vào làm ở một công ty về lập trình web dạng kha khá có tiếng).

Chuyên đề này là do mình tự tay biên soạn dựa trên kinh nghiệm ít ỏi 7 năm làm trong mảng này, mình thừa nhận mình cũng không phải là chuyên gia về mảng này nhưng có thể nói là đủ kiến thức nền và kinh nghiệm trong các dự án thực tế từ nhỏ tới tầm trung. Mong rằng những kiến thức mình đúc kết bên dưới sẽ cho bạn nguồn kiến thức bổ ích, hoặc chí ít là cũng có định hướng sẽ nên học gì tiếp theo để nâng cao trình độ mình lên.

Các bạn có thể nghĩ rằng những chuyên đề này trên mạng thiếu gì, tại sao còn làm chi cho tốn công phí sức ? Và chuyên đề này có gì đặc biệt hơn những cái đã có trước đó ?

Mình xin trả lời ngắn gọn đây chỉ là một dự án chuyên đề nhỏ của mình muốn đóng góp cho cộng đồng, những lập trình viên mới vào nghề hay những sinh viên đam mê công nghệ thông tin có thể dễ dàng tiếp cận qua những bài viết tinh gọn và trực quan. Trên mạng đã có những chuyên đề tốt hơn bằng tiếng Anh nhưng mình nghĩ rất khó để các bạn có vốn tiếng Anh không được tốt và cái nữa là do quá nhiều trang thông tin sẽ làm các bạn dễ bị nhiễu thông tin dẫn đến sai đường lạc hướng rồi kết quả không đi tới đâu.

Mọi đóng góp ý kiến, các bạn có thể comment bên dưới từng bài viết trong chuyên đề này hoặc có thể mail trực tiếp cho mình tại [email protected] !

Dưới đây là guidelines bằng tiếng Anh mình soạn ra để mình nháp bố cục nội dung sau này, tất nhiên những bài viết chuyên đề sau này tất cả sẽ bằng tiếng Việt (tất nhiên sẽ có một số từ tiếng Anh chuyên ngành không thể thay thế được).

Guidelines

Evaluate expression string with variables in PHP without eval

TLDR;

Never ever use eval function in PHP !

Updated Jul 31 : we can use Expression Language

Introduction

In some applications, we need to let user defines the expression (user lambda function) to evaluate a value or a condition. So we store user-defined expression in database then using eval function and pass variables to that function.

It works, but not securely ! Remember this important thing :

NEVER TRUST USER INPUT !

So how this article will show how we achieve the goal without touching eval or create_function function.

Idea

The idea came out when I used Ansible tool (a Pythonic dev-ops tool, with great docs and community). Ansible uses jinja template engine as mainly syntax for many thing, to render the template file and to evaluate the condition when syntax.

Same in PHP, we have Twig template engine !

Twigeval

This is my library (https://github.com/khanhicetea/twigeval) that using the above idea, one of few libraries which I write Unit Test for ;)

Installation

1
$ composer require khanhicetea/twigeval

Usage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
$cacheDir could be :
- false : no use cache (mean use eval function), be carefully !
- null : use sys_get_temp_dir() to get system temp directory as cache dir
- string : cache directory path
*/
$cacheDir = null;
$calculator = new KhanhIceTea\Twigeval\Calculator($cacheDir);

$math = $calculator->number('a / 4 + b * 3', ['a' => 16, 'b' => 3]);
// => 13

$boolean1 = $calculator->isTrue('(a and b) or c', ['a' => false, 'b' => true, 'c' => false]);
// => false

$boolean2 = $calculator->isFalse('(a and b) or c', ['a' => false, 'b' => true, 'c' => false]);
// => true

// We can even use Twig filters, functions
$string = $calculator->calculate('{{ a|reverse }} world !', ['a' => 'hello']);
// => olleh world !

Voilà !!! We have user-defined lambda function.

Feel free to contribute ! Thanks ! :)

Til next time !

#TIL : Never autostart XDebug in cli environment

TLDR;

Never ever enable xdebug.remote_autostart in cli

Xdebug is handy extension helps you debug your PHP code. But it slows the performance in cli mode, especially run PHP cli tool like composer or phpunit.

So please disable Xdebug in cli mode or set xdebug.remote_autostart=0 in INI file.

#TIL : try, catch and finally in PHP

We have to deal with exceptions every moment we touch PHP web development, and so please be carefully with running order of exception catching.

Here is an example

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php

function a() {
try {
throw new Exception('dsads');
} catch (Exception $e) {
return 'b';
} finally {
echo 'c';
}
}

echo a();

Then the output is

1
cb

Than mean even return 'b'; runs, the finally code must be runned before function result passes out.

#TIL : realpath function

If you pass a non-exists path to function realpath, it returns empty string. So please don’t do something like :

1
2
3
function storage_path($folder) {
return realpath(__DIR__.'/storage/'.$folder);
}

if you expect it return full path of new folder !

Kick start a LEMP stack on Ubuntu 16.04

LEMP = Linux + EngineX(NginX) + MySQL + PHP

Too tired for doing same tasks over and over again. I made this script to help me (and you) on kicking start a new LEMP stack on production server. Hope it useful !

What does script do :

  • Disable IPv6 (it’s not ready for production at the moment)
  • Configure firewall (only accepts port 22, 80 and 443)
  • Disable password authentication to SSH service
  • Upgrade system
  • Install useful tools (git, screen, vim, curl and lego for LetsEncrypt ACME)
  • NginX
  • MySQL 5.7 (default root password is passwd, should be changed ASAP)
  • PHP 7.1 (with production .ini)
  • Composer (PHP package manager)
  • AND last but not least, a congratuation message !
  • Fully and updated script : check my repo here

Here is the script :

STOP DOING SAME THING BUT EXPECTING DIFFERENT RESULTS