Langsung memodifikasi superglobals

20

Saya telah melihat orang (yang umumnya menulis kode yang baik) langsung mengubah $_POSTarray dengan kode seperti ini:

// Add some value that wasn't actually posted
$_POST['last_activity'] = time();

// Alter an existing post value
$_POST['name'] = trim($_POST['name']);

// Our pretend function
// Pass the entire $_POST array as data to work with in the function
// The function update_record() will read only the values we actually need
update_record($_POST);

// ...That sure was easier than creating a new array 
//  with only the $_POST values we actually need.

Masuk akal bahwa update_record()seharusnya tidak mengakses $ _POST secara langsung, jadi kita dapat mengirimkan array data lain misalnya, tetapi tentu ini malas, desain yang buruk, atau mungkin hanya salah? Namun, kami masih meneruskan array yang valid update_record(), jadi mengapa membuat yang baru?

Ini bukan inti dari pertanyaan, hanya sebuah contoh penggunaan. Namun, saya telah mendengar banyak orang mengatakan bahwa ini tidak boleh dilakukan dengan $_REQUESTdata, dan itu praktik yang buruk. Tapi kenapa? Terlihat tidak berbahaya.

Contoh:

  • Menetapkan nilai default $_GET(atau posting) yang tidak benar-benar ada

  • Menambahkan $_POSTnilai yang tidak benar-benar diposting setelah pengiriman formulir

  • Sanitasi langsung atau memfilter nilai $_GETarray atau kunci sangat awal dalam skrip (sanitasi fallback ... mengapa tidak?)

  • Menetapkan $_POSTnilai secara manual sebelum pengiriman formulir untuk mengisi input dengan nilai default (ketika input membaca $_POSTuntuk nilai standarnya; Saya telah melakukan ini)

  • Membuat $_SERVERnilai - nilai Anda sendiri ? Tentu, hei kenapa tidak?

  • Bagaimana dengan yang lain, suka $_COOKIEdan tidak $_SESSION? Tentu saja kita harus memodifikasinya secara langsung bukan? Lalu mengapa tidak yang lain?

Haruskah modifikasi superglobals langsung tidak pernah dilakukan, atau apakah boleh dilakukan dalam beberapa kasus?

Wesley Murch
sumber
Saya setuju dengan # 1, # 2, dan # 3 karena ini adalah penggunaan yang tidak terduga (terutama # 1 dan # 2).
Kevin Peno
Pertanyaan bagus. Mengubah array global salah dengan cara yang sama menggunakan nilai global salah. Array ini juga memiliki tujuan mereka (melewati parameter dari luar) yang membuat mereka mengubah cara langsung untuk mengacaukan dalam kode. Tapi, saya percaya beberapa array ini dapat dibersihkan pada awal skrip, hanya saja tidak menyebabkan masalah dalam kode.
Tadeck
1
Saya menggunakan pembungkus array input OO (pemfilteran implisit), yang mencetak pemberitahuan tambahan saat variabel $ _GET atau $ _POST dirusak. Itu masih mungkin, tetapi harus dibatasi pada situasi yang sempit. (Pensinyalan lintas-modul, meskipun hanya operator / pengontrol depan yang memerlukannya.)
mario
@ Mario: Saya ingin mendengar lebih banyak tentang bagaimana Anda mencapai itu jika Anda dapat melihat pertanyaan ini: stackoverflow.com/questions/12954656
Wesley Murch

Jawaban:

16

Mengingat PHP sudah mengatur superglobals itu, saya tidak berpikir itu jahat untuk memodifikasinya. Dalam beberapa kasus, ini mungkin cara terbaik untuk menyelesaikan masalah ... terutama ketika berhadapan dengan kode pihak ketiga yang tidak mudah Anda modifikasi. (Mereka mungkin menggunakan $_GETsecara langsung atau menganggap beberapa kunci ada $_SERVER, dll.)

Namun, secara umum, saya pikir ini adalah praktik yang buruk ketika Anda menulis kode Anda sendiri. Memodifikasi $_REQUESTdata dengan beberapa filter di balik layar yang berjalan pada setiap halaman secara otomatis cenderung menimbulkan efek samping. (Lihat semua masalah yang disebabkan "kutipan sihir" sebagai bukti.)

Jadi, jika Anda tidak akan melakukan itu (secara otomatis menyaring superglobals), maka yang berikut ini tidak memberi Anda manfaat:

$_POST['foo'] = filter($_POST['foo']);

ketika Anda dapat dengan mudah melakukannya:

$foo = filter($_POST['foo']);

Saya pikir itu jauh lebih jelas untuk membuat perbedaan situs-lebar yang $_POSTdan $_GETyang selalu tanpa filter, data yang tidak dipercaya, dan mereka harus tidak pernah digunakan sebagai-adalah.

Dengan menyalin nilai yang difilter ke variabel lain, Anda membuat klaim bahwa, "Saya mengerti apa yang saya lakukan ... Saya telah memfilter input ini, dan aman untuk digunakan."

konforce
sumber
Terima kasih atas masukannya, internet saya sudah hampir 2 hari tidak ada sehingga saya belum punya kesempatan untuk membalas kepada siapa pun. Dalam contoh ini, saya memodifikasi $ _POST dan menggunakannya sebagai larik data untuk dilewatkan ke fungsi pembaruan, dengan anggapan ada beberapa kunci $ _POST lainnya yang akan kita baca dalam fungsi itu. Saya lebih suka membuat array baru tetapi saya telah melihat orang-orang melakukan ini sebagai gantinya, jadi saya masih agak tidak yakin apakah menyebutnya "kode buruk", tapi saya pikir setidaknya condong ke arah itu. Saya pikir setiap kali Anda merasa perlu melakukan ini, selalu ada cara yang lebih baik.
Wesley Murch
1
@Wesley, alasan utama itu "buruk" adalah karena itu membuatnya jauh lebih mungkin bahwa Anda akan lupa untuk membersihkan beberapa data pengguna. Dalam contoh Anda, Anda memodifikasi satu kunci lalu melewati seluruh larik. Bagaimana jika sebagian dari data itu mengandung input berbahaya yang tidak diproses? Jauh lebih baik untuk membangun array baru itu dengan tangan, hanya menyalin hal-hal yang Anda perlukan $_POST, membersihkannya seiring berjalannya waktu. Dan mengenai orang lain yang melakukan ini ... yah, banyak orang menulis kode PHP yang sangat buruk, tapi itu bukan alasan untuk Anda juga. :)
konforce
Saya pikir saya harus menekankan aplikasi lain dari penyalahgunaan superglobals selain hanya membersihkan data. Saya mungkin harus meninggalkannya sama sekali dan menulis pertanyaan yang lebih jelas, orang-orang terutama suka mengambil aspek keamanan dan sering mengabaikan sisanya. Tidak terdengar tidak berterima kasih, saya sangat menghargai umpan baliknya. Saya akan menunggu satu hari dan memberikan satu ini tanda centang, karena Anda telah membahas beberapa poin bagus tetapi melewatkan partai pemilih selama 3 menit ketika pertanyaannya baru :) Terima kasih lagi!
Wesley Murch
9

Saya biasanya menyarankan agar Anda tidak mengubah super-global yang telah ditentukan sebelumnya sehingga jelas apa data yang disanitasi dan data mentah / tidak dipercaya.

Orang lain mungkin menyarankan bahwa jika Anda membersihkan superglobals pada awal siklus permintaan maka Anda tidak perlu khawatir tentang mereka di tempat lain.

Saya selalu mencocokkannya saat Anda membutuhkannya:

$id = (int)$_POST['id'];

atau serupa.

Dalam hal variabel lain itu praktek yang baik untuk tidak menulis ke salah $_GET, $_POST, $_REQUEST, $_SERVERatau $_COOKIE. $_SESSIONNamun berbeda karena Anda sering ingin menulis data ke sesi yang kemudian bertahan di berbagai permintaan dalam sesi.


sumber
2
Lebih banyak alasan mengapa jenis global ini harus pergi diganti dengan objek / metode yang dapat dipanggil untuk mendapatkannya saat diperlukan. Mengapa setcookieada, tetapi kami mendapat cookie melalui $_COOKIE? Juga, karena $_COOKIEhanya diatur ketika sesi saat ini dimulai, dan tidak pernah diperbarui, itu mengharuskan Anda mengubah / mengatur cookie di kedua area sehingga area kode selanjutnya memiliki informasi terkini.
Kevin Peno
Terima kasih James, saya sudah offline untuk sementara waktu sehingga saya tidak bisa menjawab. Singkat cerita - saya setuju dengan Anda. Selalu ada solusi yang lebih baik daripada menulis ke postingan / mendapatkan / etc, tapi saya masih tidak yakin apakah itu dianggap ide yang benar-benar buruk, seperti dalam " tidak pernah melakukan ini pernah ". Jadi, jika saya menemukan jenis kode ini lagi, apakah Anda pikir saya memiliki hak untuk "memanggil mereka" pada kode ceroboh, atau bisakah ini digunakan dengan cara yang cerdas dan aman kadang-kadang?
Wesley Murch
@Wesley Jika itu akan "tidak pernah melakukan ini" superglobals mungkin hanya akan menjadi read-only - mereka tidak. Saya hanya menyebutnya praktik buruk untuk mengatur atau menimpa mereka dalam kode aplikasi Anda - untuk alasan tersebut.
Michel Feldheim
3

Anda harus menghindarinya. Mungkin suatu saat Anda lupa membersihkan sesuatu, maka Anda dapat mengambil data berbahaya. Jika Anda menyalin data ke struktur baru saat membersihkan

  • Anda hanya mendapatkan, apa yang Anda inginkan / butuhkan dan bukan apa yang ada di $_POSTdalamnya juga
  • Anda mungkin akan mendapatkan kesalahan, jika array yang baru dibuat kehilangan beberapa kunci atau hilang sama sekali

Skrip lain tambahan mungkin berasumsi, bahwa array tidak tersentuh dan mungkin bereaksi penasaran.

KingCrunch
sumber
2

Saya tidak pernah menyukai gagasan memodifikasi superglobal karena itu menyesatkan. Ini adalah cara cepat untuk melakukan sesuatu yang hampir pasti ada cara yang lebih baik untuk dilakukan.

Jika Anda mengubah nilai $_POST, misalnya, maka Anda mengatakan bahwa perangkat lunak menerima data yang tidak.

MASALAH NYATA

Ada situasi kehidupan nyata di mana ini menjadi masalah besar:

Bayangkan Anda bekerja dalam sebuah tim. Di dunia yang ideal, semua orang menggunakan sintaksis yang sama, tetapi kita tidak hidup di dunia yang ideal. Salah satu pengembang, John, suka mengakses data yang diposting menggunakan $_POST. Dia mengubah sesuatu di post vars:

$_POST['ranking'] = 2; // John has changed ranking from 1 to 2 for whatever reason

Kemudian Anda memiliki pengembang lain, Chris, yang lebih suka menggunakan filter_inputuntuk mengakses data yang dimasukkan (yaitu GET, POST, SERVER, COOKIE) untuk melindungi perangkat lunak saat memproses data yang dapat diubah oleh pengguna. Di bagian perangkat lunaknya, ia perlu mendapatkan nilai posting ranking. Bagiannya dari kode adalah SETELAH milik John.

$ranking = filter_input(INPUT_POST, 'ranking', FILTER_SANITIZE_NUMBER_INT);
// $ranking = 1

Dari contoh di atas, dengan mengubah superglobal, Anda telah merusak PHP. John telah menetapkan nilai $_POST['ranking']ke 2 untuk alasan apa pun, tetapi sekarang Chris telah menerima nilai 1

Ketika saya tidak melihat cara lain untuk melakukannya:

Saya bekerja pada sebuah proyek yang menggunakan wordpress sebagai blognya di belakang load-balancer AWS. Ini mengubah nilai $_SERVER['remote_address']. Dalam hal ini, pengembang lain tidak punya pilihan selain melakukan hal berikut:

if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
    $parts = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
    $_SERVER['REMOTE_ADDR'] = $parts[0];
}

Kesimpulan

Hampir pasti ada cara yang lebih baik daripada mengganti superglobals

Luke Madhanga
sumber
1

Saya pikir pertanyaan sebenarnya di sini adalah "mengapa Anda harus memodifikasi tema?". Saya tidak melihat alasan yang sah untuk melakukannya. Jika Anda perlu membersihkan imput, Anda mungkin ingin menggunakan variabel lokal ...

Kecuali jika kode Anda cukup pendek (katakanlah, panjangnya kurang dari 50 baris), memodifikasi yang super global hanya akan membuat kode Anda lebih sulit untuk dipelihara dan undersand.

Omong-omong, Anda tidak perlu meneruskan $ _POST ke fungsi, karena ini adalah array superglobal yang dapat diakses bahkan dalam lingkup fungsi lokal.


sumber
3
Tapi dia harus melewatinya. Lain lagi sangat sulit untuk diuji dan tidak mungkin untuk memanggil fungsi / metode dengan nilai lain tanpa ada peretasan (bahkan lebih buruk)
KingCrunch
Yah, itu tergantung pada apa metode yang dilakukannya. Jika ia dirancang hanya untuk mem-parsing apa pun yang ada di array $ _POST, ia tidak perlu meneruskannya. Tentu saja, jika itu melayani tujuan yang lebih umum / abstrak, daripada Anda benar.
2
@ Thomas, saya setuju dengan Raja di sini. Sekalipun bersifat global, Anda tidak boleh menggunakan apa pun global dalam lingkup lain karena menyebabkan kopling ketat (itulah sebabnya fungsi tidak dapat digunakan kembali). Dengan contoh Anda, jika fungsinya untuk membersihkan data, mengapa hanya membersihkan $_POSTdata? Melewati $_POSTmembuat fungsi membersihkan data apa pun .
Kevin Peno
0

Setelah awalnya menjawab pertanyaan ini dengan mengatakan seharusnya tidak ada alasan untuk memodifikasi superglobals, saya mengedit jawaban ini dengan contoh saat saya memutuskan untuk melakukannya.

Saat ini saya sedang mengerjakan tabel database penulisan ulang URL di mana requestkolom mengarahkan pengguna ke targetkolom yang sesuai .

Misalnya, requestmungkin blog/title-heredan targetmungkin blog.php?id=1.

Karena blog.phpmengharapkan $_GETvariabel, dan saya tidak ingin mengubah header("Location:"), saya melakukan sesuatu seperti ini:

$uri    = explode('?', $uri_request)[0];
$params = explode('?', $uri_request)[1];
parse_str($params, $_GET);

Ini menciptakan $_GETlarik yang berisi parameter yang dimaksudkan dilewatkan oleh targetkolom.

Pada akhirnya, saya akan sangat menyarankan untuk memodifikasi superglobals kecuali Anda benar-benar harus melakukannya .

rybo111
sumber