Semoga harimu menyenangkan. Ini adalah artikel pertama dalam seri PHP untuk pengembang pemula. Ini akan menjadi serangkaian artikel yang tidak biasa, tidak akan ada
echo "Hello World"
, akan ada hardcore dari kehidupan programmer PHP dengan campuran kecil dari "pekerjaan rumah" untuk mengkonsolidasikan materi.
Saya akan mulai dengan sesi - ini adalah salah satu komponen terpenting yang harus Anda kerjakan. Tidak memahami prinsip kerjanya - berbisnis. Jadi untuk menghindari masalah, saya akan mencoba berbicara tentang semua kemungkinan nuansa.
Tetapi sebagai permulaan, untuk memahami mengapa kita perlu sesi, kita beralih ke asal-usul - ke protokol HTTP.
Protokol HTTP
Protokol HTTP adalah HyperText Transfer Protocol - "Hypertext Transfer Protocol" - yaitu. sebenarnya - protokol teks, dan memahaminya tidak sulit.
Awalnya, dipahami bahwa di bawah protokol ini hanya HTML yang akan dikirimkan, alamat dan nama, tetapi sekarang mereka tidak akan mengirim dan = ^. ^ = Dan οΌβ’ _ γ
_ β’οΌ
Agar tidak bertele-tele, izinkan saya memberi Anda contoh komunikasi melalui protokol HTTP.
Berikut adalah contoh permintaan bagaimana browser Anda mengirimkannya ketika Anda meminta halaman
http://example.com
:
GET / HTTP/1.1 Host: example.com Accept: text/html < >
Dan berikut ini contoh responsnya:
HTTP/1.1 200 OK Content-Length: 1983 Content-Type: text/html; charset=utf-8 <html> <head>...</head> <body>...</body> </html>
Ini adalah contoh yang sangat disederhanakan, tetapi bahkan di sini Anda dapat melihat apa yang terdiri dari permintaan dan respons HTTP:
- garis start - untuk permintaan berisi metode dan jalur halaman yang diminta, untuk respons - versi protokol dan kode respons
- header - memiliki format nilai kunci yang dipisahkan oleh titik dua, setiap heading baru ditulis dari baris baru
- isi pesan - baik secara langsung HTML atau data dipisahkan dari header dengan dua jeda baris, mungkin tidak ada, seperti dalam permintaan di atas
Jadi, kami menemukan protokolnya - itu sederhana, protokol ini telah memimpin sejarahnya sejak tahun 1992, jadi Anda tidak akan menamakannya ideal, tetapi apa itu - kirim permintaan - dapatkan jawaban, dan hanya itu, server dan klien tidak lagi terhubung. Tetapi skenario seperti itu tidak berarti satu-satunya yang mungkin, kita dapat memiliki otorisasi, server harus entah bagaimana memahami bahwa permintaan ini berasal dari pengguna tertentu, yaitu klien dan server harus berkomunikasi dalam sesi tertentu. Dan ya, mekanisme berikut diciptakan untuk ini:
- Ketika pengguna mengotorisasi, server menghasilkan dan mengingat kunci unik - pengidentifikasi sesi, dan melaporkannya ke browser
- Browser menyimpan kunci ini, dan dengan setiap permintaan berikutnya, ia mengirim
Untuk menerapkan mekanisme ini,
cookie dibuat (cookie, cookie) - file teks sederhana di komputer Anda, berdasarkan file untuk setiap domain (meskipun beberapa browser lebih maju dan menggunakan database SQLite untuk menyimpan), sementara browser memaksakan batasan jumlah catatan dan ukuran data yang disimpan (untuk sebagian besar browser ini adalah 4096 byte, lihat
RFC 2109 dari 1997)
Yaitu Jika Anda mencuri cookie dari browser Anda, dapatkah Anda pergi ke halaman Facebook Anda atas nama Anda? Jangan khawatir, ini tidak dapat dilakukan, setidaknya dengan facebook, dan kemudian saya akan menunjukkan kepada Anda salah satu cara yang mungkin untuk melindungi dari jenis serangan terhadap pengguna Anda.
Sekarang mari kita lihat bagaimana respons permintaan kita berubah, ada otorisasi:
Minta POST /login/ HTTP/1.1 Host: example.com Accept: text/html login=Username&password=Userpass
Metode kami telah berubah menjadi POST, dan login dan kata sandi dikirimkan dalam tubuh permintaan. Jika Anda menggunakan metode GET, string kueri akan berisi nama pengguna dan kata sandi, yang tidak terlalu benar dari sudut pandang ideologis, dan memiliki sejumlah efek samping dalam bentuk pencatatan (misalnya, dalam
access.log
sama) dan caching kata sandi dalam bentuk yang jelas.
Tanggapan HTTP/1.1 200 OK Content-Type: text/html; charset=utf-8 Set-Cookie: KEY=VerySecretUniqueKey <html> <head>...</head> <body>...</body> </html>
Respons server akan berisi tajuk
Set-Cookie: KEY=VerySecretUniqueKey
, yang akan memaksa browser untuk menyimpan data ini dalam cookie, dan saat berikutnya mengakses server, itu akan dikirim dan dikenali oleh server:
Minta GET / HTTP/1.1 Host: example.com Accept: text/html Cookie: KEY=VerySecretUniqueKey < >
Seperti yang Anda lihat, tajuk yang dikirim oleh browser (Tajuk Permintaan) dan server (Tajuk Respons) berbeda, meskipun ada kesamaan untuk permintaan dan respons (Tajuk Umum)
Server mengenali pengguna kami dengan cookie yang dikirim dan selanjutnya akan memberinya akses ke informasi pribadi. Jadi, well, semacam sesi dan HTTP yang diurutkan, sekarang Anda dapat kembali ke PHP dan fitur-fiturnya.
PHP dan sesi
Saya harap Anda sudah menginstal PHP di komputer Anda, sebagai Selanjutnya saya akan memberikan contoh, dan mereka harus dijalankan
Bahasa PHP dibuat agar sesuai dengan protokol HTTP - yaitu Tugas utamanya adalah untuk memberikan jawaban atas permintaan HTTP dan untuk "mati" membebaskan memori dan sumber daya. Oleh karena itu, mekanisme sesi tidak berfungsi dalam PHP dalam mode otomatis, tetapi dalam mode manual, dan Anda perlu tahu apa yang harus dipanggil, dan dalam urutan apa.
Di sini Anda memiliki artikel tentang topik yang dimaksudkan untuk mati PHP , atau di sini dalam bahasa Rusia , tetapi lebih baik untuk meletakkannya di bookmark "untuk nanti".
Pertama-tama, Anda perlu "memulai" sesi - untuk ini kami menggunakan fungsi
session_start () , membuat file
session.start.php dengan konten berikut:
<?php session_start();
Jalankan
server web PHP
bawaan di folder dengan skrip Anda:
php -S 127.0.0.1:8080
Buka browser dan buka Alat Pengembang (atau
apa pun ), lalu buka halaman
http://127.0.0.1:8080/session.start.php - Anda seharusnya hanya melihat halaman kosong, tetapi jangan buru-buru menutup - lihat ke tajuk yang dikirimkan server kepada kami:

Akan ada banyak hal, kami hanya tertarik pada baris ini dalam respons server (cookie bersih, jika tidak ada baris seperti itu, dan segarkan halaman):
Set-Cookie: PHPSESSID=dap83arr6r3b56e0q7t5i0qf91; path=/
Setelah melihat ini, browser akan menyimpan cookie bernama `PHPSESSID`:

PHPSESSID
- nama sesi default, itu disesuaikan dari konfigurasi php.ini dengan direktif session.name , jika perlu, nama dapat diubah dalam file konfigurasi itu sendiri atau menggunakan fungsi session_name () fungsi
Dan sekarang - kita me-refresh halaman, dan kita melihat bahwa browser mengirimkan cookie ini ke server, Anda dapat mencoba me-refresh halaman beberapa kali, hasilnya akan sama:

Total yang kita miliki - teorinya bertepatan dengan praktik, dan ini baik-baik saja.
Langkah selanjutnya adalah menyimpan nilai arbitrer ke dalam sesi, untuk ini, variabel super global
$_SESSION
digunakan dalam PHP, kami akan menghemat waktu saat ini - untuk melakukan ini, panggil fungsi
date () :
session_start(); $_SESSION['time'] = date("H:i:s"); echo $_SESSION['time'];
Kami menyegarkan halaman dan melihat waktu server, memperbarui lagi - dan waktu telah diperbarui. Sekarang mari kita pastikan bahwa waktu yang diset tidak berubah dengan setiap penyegaran halaman:
session_start(); if (!isset($_SESSION['time'])) { $_SESSION['time'] = date("H:i:s"); } echo $_SESSION['time'];
Kami memperbarui - waktu tidak berubah, apa yang dibutuhkan. Tetapi pada saat yang sama, kita ingat bahwa PHP sedang sekarat, yang berarti ia menyimpan sesi ini di suatu tempat, dan kita akan menemukan tempat ini ...
Segalanya rahasia menjadi jelas
Secara default, PHP menyimpan sesi dalam file - direktif
session.save_handler bertanggung jawab untuk ini, mencari path tempat file disimpan dalam direktif
session.save_path , atau menggunakan fungsi
session_save_path () untuk mendapatkan path yang diperlukan.
Dalam konfigurasi Anda, jalur ke file mungkin tidak ditentukan, maka file sesi akan disimpan dalam file sementara sistem Anda - panggil fungsi sys_get_temp_dir () dan cari tahu di mana tempat tersembunyi ini.
Jadi, kami menyusuri jalur ini dan menemukan file sesi Anda (saya punya file ini
sess_dap83arr6r3b56e0q7t5i0qf91
), buka di editor teks:
time|s:8:"16:19:51";
Seperti yang Anda lihat, ini saatnya kita, ini adalah format rumit sesi kita, tetapi kita dapat membuat perubahan, mengubah waktu, atau kita cukup memasukkan baris apa saja, mengapa tidak:
time|s:13:"\m/ (@.@) \m/";
Untuk mengonversi string ini menjadi array, Anda perlu menggunakan fungsi
session_decode () , untuk konversi balik -
session_encode () - ini disebut serialisasi, hanya dalam PHP untuk sesi - ini sendiri - khusus, meskipun Anda dapat menggunakan
serialisasi PHP standar - tulis dalam direktif konfigurasi
sesi - tulis dalam direktif konfigurasi
sesi Nilai
.serialize_handler adalah
php_serialize
dan Anda akan bahagia, dan
$_SESSION
dapat digunakan tanpa batasan - sekarang Anda dapat menggunakan angka dan karakter khusus sebagai indeks
|
dan
!
dalam nama (untuk semua 10+ tahun kerja, saya tidak pernah harus :)
TugasTulis fungsi Anda, mirip fungsinya dengan
session_decode()
, di sini Anda memiliki kumpulan data uji untuk sesi (tidak diperlukan untuk menyelesaikan pengetahuan tentang ekspresi reguler), ambil teks untuk konversi dari file sesi Anda saat ini:
$_SESSION['integer var'] = 123; $_SESSION['float var'] = 1.23; $_SESSION['octal var'] = 0x123; $_SESSION['string var'] = "Hello world"; $_SESSION['array var'] = array('one', 'two', [1,2,3]); $object = new stdClass(); $object->foo = 'bar'; $object->arr = array('hello', 'world'); $_SESSION['object var'] = $object; $_SESSION['integer again'] = 42;
Jadi apa yang belum kita coba? Itu benar - untuk mencuri cookie, mari kita luncurkan browser lain dan tambahkan cookie yang sama ke dalamnya. Untuk ini saya menulis javascript sederhana untuk Anda, salin ke konsol browser dan jalankan, ingatlah untuk mengubah pengidentifikasi sesi ke Anda sendiri:
javascript:(function(){document.cookie='PHPSESSID=dap83arr6r3b56e0q7t5i0qf91;path=/;';window.location.reload();})()
Sekarang kedua browser Anda sedang melihat sesi yang sama. Saya sebutkan di atas bahwa saya akan berbicara tentang metode perlindungan, pertimbangkan cara paling sederhana - kami akan mengikat sesi ke browser, lebih tepatnya, dengan bagaimana browser muncul ke server - kami akan mengingat
User-Agent dan memeriksanya setiap saat:
session_start(); if (!isset($_SESSION['time'])) { $_SESSION['ua'] = $_SERVER['HTTP_USER_AGENT']; $_SESSION['time'] = date("H:i:s"); } if ($_SESSION['ua'] != $_SERVER['HTTP_USER_AGENT']) { die('Wrong browser'); } echo $_SESSION['time'];
Lebih sulit untuk dipalsukan, tetapi masih mungkin, tambahkan tabungan dan periksa
$_SERVER['REMOTE_ADDR']
dan
$_SERVER['HTTP_X_FORWARDED_FOR']
, dan ini akan lebih seperti perlindungan terhadap penyusup yang menyusup ke cookie kami.
Kata kunci dalam paragraf sebelumnya sepertinya cookie telah berjalan di atas protokol HTTPS dalam proyek nyata untuk waktu yang lama, jadi tidak ada yang bisa mencurinya tanpa akses fisik ke komputer atau smartphone Anda
Perlu disebutkan
direktif session.cookie-httponly , berkat itu cookie sesi tidak dapat diakses dari JavaScript. Selain itu, jika Anda melihat manual fungsi
setcookie () , Anda akan melihat bahwa parameter terakhir juga bertanggung jawab untuk HttpOnly. Ingat ini - pengaturan ini memungkinkan Anda untuk secara efektif menangani serangan XSS di hampir
semua browser .
TugasTambahkan cek ke IP pengguna dalam kode, jika cek gagal, hapus sesi yang dikompromikan.
Langkah demi langkah
Dan sekarang saya akan menjelaskan dalam langkah-langkah algoritma bagaimana sesi bekerja di PHP, menggunakan kode berikut sebagai contoh (pengaturan default):
session_start(); $_SESSION['id'] = 42;
- setelah memanggil
session_start()
PHP mencari cookie untuk pengidentifikasi sesi dengan nama yang ditentukan dalam session.name
- ini adalah PHPSESSID
- jika tidak ada pengenal, maka itu dibuat (lihat session_id () ), dan membuat file sesi kosong di sepanjang
session.save_path
sess_{session_id()}
dengan nama sess_{session_id()}
, header akan ditambahkan ke respons server, untuk mengatur cookie {session_name()}={session_id()}
- jika pengenal ada, maka cari file sesi di folder
session.save_path
:
- kami tidak menemukannya - kami membuat file kosong dengan nama
sess_{$_COOKIE[session_name()]}
(pengidentifikasi hanya dapat berisi karakter dari rentang az
, AZ
, 0-9
, koma dan tanda minus) - temukan, baca file, dan uraikan data (lihat session_decode () ) ke variabel super global
$_SESSION
(file dikunci untuk membaca / menulis)
- ketika skrip telah selesai bekerja, maka semua data dari
$_SESSION
dikemas menggunakan session_encode()
ke dalam file di sepanjang path session.save_path
bernama sess_{session_id()}
(kunci dilepaskan)
TugasTetapkan nilai cookie sewenang-wenang di browser Anda dengan nama PHPSESSID
, biarkan 1234567890
, segarkan halaman, periksa apakah Anda telah membuat file baru sess_1234567890
Apakah ada kehidupan tanpa cookie?
PHP dapat bekerja dengan sesi meskipun cookie dinonaktifkan di browser, tetapi kemudian semua URL di situs akan berisi parameter dengan pengidentifikasi sesi Anda, dan ya - apakah Anda masih perlu mengkonfigurasi ini, tetapi apakah Anda memerlukannya? Saya tidak harus menggunakannya, tetapi jika saya benar-benar ingin, saya hanya akan mengatakan di mana untuk menggali:
Dan jika Anda perlu menyimpan sesi dalam basis data?
Untuk menyimpan sesi dalam basis data, Anda perlu mengubah penyimpanan sesi dan memberi tahu PHP cara menggunakannya. Untuk tujuan ini, antarmuka
SessionHandlerInterface dan fungsi
session_set_save_handler telah dibuat.
Secara terpisah, saya perhatikan bahwa Anda tidak perlu menulis penangan sesi Anda sendiri untuk redis dan memcache - ketika Anda menginstal ekstensi ini, penangan yang sesuai juga ikut serta, jadi RTFM adalah segalanya. Baiklah dan ya, pawang harus ditentukan sebelum memanggil session_start()
;)
TugasTerapkan SessionHandlerInterface
untuk menyimpan sesi di MySQL, periksa apakah itu berfungsi.
Ini adalah tugas asterisk bagi mereka yang sudah terbiasa dengan database.
Kapan sesi ini mati?
Arahan
session.gc_maxlifetime bertanggung jawab atas masa pakai sesi. Secara default, arahan ini sama dengan 1440 detik (24 menit), harus dipahami sehingga jika sesi belum diakses untuk waktu yang ditentukan, maka sesi akan dianggap "busuk" dan akan menunggu gilirannya untuk dihapus.
Pertanyaan lain yang menarik, dapatkah Anda menanyakannya kepada pengembang yang sudah matang - kapan PHP menghapus file dari sesi yang kadaluwarsa? Jawabannya ada di panduan resmi, tetapi tidak secara eksplisit - jadi ingat:
Pengumpulan sampah dapat dimulai ketika fungsi
session_start()
dipanggil, probabilitas memulai tergantung pada dua arahan
session.gc_probability dan
session.gc_divisor , tindakan pertama sebagai dividen, tindakan kedua sebagai pembagi, dan secara default nilai-nilai ini adalah 1 dan 100, dll. e. kemungkinan kolektor akan diluncurkan dan file sesi akan dihapus sekitar 1%.
TugasUbah nilai direktif session.gc_divisor
sehingga pengumpul sampah mulai setiap waktu, periksa apakah ini terjadi.
Kesalahan paling sepele
Kesalahan dengan lebih dari setengah juta hasil dalam hasil Google:
Tidak dapat mengirim cookie sesi - tajuk sudah dikirim oleh
Tidak dapat mengirim pembatas cache sesi - tajuk sudah dikirim
Untuk memperolehnya, buat file
session.error.php dengan konten berikut:
echo str_pad(' ', ini_get('output_buffering')); session_start();
Di baris kedua, "sihir" aneh adalah fokus dengan buffer output, saya akan membicarakannya di salah satu artikel berikut, sejauh ini menganggap ini hanya string dengan panjang 4.096 karakter, dalam hal ini semua spasi
Mulailah dengan menghapus cookie sebelumnya dan Anda akan mendapatkan kesalahan di atas, meskipun teks kesalahannya berbeda, tetapi intinya sama: kereta telah pergi - server telah mengirim konten halaman ke browser dan sudah terlambat untuk mengirim header, ini tidak akan berfungsi di cookie dan pengenal sesi yang disukai tidak muncul di cookie. Jika Anda mengalami kesalahan ini - cari tempat di mana teks ditampilkan sebelumnya, mungkin ada spasi sebelum karakter
<?php
, atau setelah
?>
Dalam salah satu file yang terhubung, dan baik, jika itu adalah ruang, mungkin ada beberapa utas yang tidak dapat dicetak seperti
BOM , jadi berhati-hatilah, dan infeksi ini tidak akan memengaruhi Anda (lagipula ... tawa homerik).
TugasUntuk menguji pengetahuan ini, saya ingin Anda menerapkan mekanisme sesi Anda sendiri dan membuat kode di atas berfungsi:
require_once 'include/sess.php'; sess_start(); if (isset($_SESS["id"])) { echo $_SESS["id"]; } else { $_SESS["id"] = 42; }
Untuk mengimplementasikan rencana Anda, Anda akan memerlukan fungsi register_shutdown_function ()
Kunci
Kesalahan umum lainnya di antara pemula adalah upaya untuk membaca file sesi saat dikunci oleh skrip lain. Sebenarnya, ini bukan kesalahan, ini adalah kesalahpahaman tentang prinsip pemblokiran :)
Tapi mari kita ambil langkah-langkahnya lagi:
session_start()
tidak hanya membuat / membaca file, tetapi juga menguncinya sehingga tidak ada yang dapat membuat perubahan saat skrip dieksekusi, atau membaca data yang tidak konsisten dari file sesi- kunci dilepaskan di akhir skrip
"Menempel" ke dalam kesalahan ini sangat mudah, buat dua file:
Sekarang, jika Anda membuka halaman
lock.php
di browser, dan kemudian buka
start.php
di tab baru, Anda akan melihat bahwa halaman kedua hanya akan terbuka setelah skrip pertama dijalankan, yang memblokir file sesi selama 10 detik.
Ada beberapa pilihan untuk menghindari fenomena seperti itu - "kikuk" dan "bijaksana".
"Kapak"Gunakan pengendali sesi khusus untuk "lupa" menerapkan penguncian :)
Opsi yang sedikit lebih baik adalah mengambil yang sudah jadi dan menonaktifkan kunci (misalnya, memcached memiliki opsi seperti itu -
memcached.sess_locking ) O_o
Luangkan berjam-jam kode debug untuk mencari kesalahan sembulan yang langka ...
"Bijaksana"Di mana cara terbaik - untuk memantau sesi mengunci sendiri, dan menghapusnya ketika tidak diperlukan:
- Jika Anda yakin tidak perlu melakukan perubahan pada data sesi, gunakan opsi
read_and_close
saat memulai sesi:
session_start([ 'read_and_close' => true ]);
Dengan demikian, kunci akan dirilis segera setelah membaca data sesi.
- Jika Anda masih perlu membuat perubahan pada sesi, maka setelah menutup sesi dari rekaman:
session_start();
TugasDaftar dua file lock.php
dan lock.php
sedikit lebih tinggi. Buat lebih banyak write-close.php
read-close.php
dan write-close.php
, di mana Anda akan mengontrol penguncian dengan cara yang tercantum. Periksa cara kerja kunci (atau tidak berfungsi).
Kesimpulannya
Dalam artikel ini, Anda telah diberikan tujuh tugas, sementara itu tidak hanya bekerja dengan
sesi , tetapi juga memperkenalkan Anda ke
fungsi MySQL dan
string . Untuk asimilasi bahan ini - Anda tidak perlu artikel terpisah, cukup manual pada tautan yang disediakan cukup - tidak ada yang akan membacanya untuk Anda. Lakukan itu!
PS Jika Anda mempelajari sesuatu yang baru dari artikel - terima kasih penulis - bagikan artikel di jejaring sosial;)
PPS Ya, ini adalah artikel lintas-posting dari
blog saya, tetapi masih relevan :)
Serangkaian artikel "PHP untuk pemula":