PHP “php: // input” ve $ _POST karşılaştırması


243

JQuery Ajax istekleri ile etkileşim php://inputyerine yöntemi kullanmak için yönlendirildi $_POST. Anlamadığım şey, bu yöntemi $_POSTveya global yöntemle kullanmanın yararlarıdır $_GET.


2
Ben bu yazı üzerine tökezleme ve onun müthiş cevapları okuma önce PHP tarafında ajax çağrıları almak için "kesmek" kullanmak için kullanılır! Gelecekte aynı sorunu olan diğer insanlar için, umarım arama motorları da yorumumu okuyacak! :)
aderchox

Yanıtlar:


484

Bunun nedeni, php://inputiçerik türünden bağımsız olarak, isteğin HTTP üstbilgilerinden sonra tüm ham verileri döndürmesidir.

PHP Süper küresel $_POST, sadece gerekiyordu ya olduğu sarma verilerinin

  • application/x-www-form-urlencoded (basit form gönderileri için standart içerik türü) veya
  • multipart/form-data (çoğunlukla dosya yüklemeleri için kullanılır)

Bunun nedeni, bunların kullanıcı aracıları tarafından desteklenmesi gereken tek içerik türleri olmasıdır . Bu nedenle sunucu ve PHP geleneksel olarak başka bir içerik türü almayı beklemez (bu, yapamayacakları anlamına gelmez).

Yani, eski güzel bir HTML'yi POST yaparsanız form, istek şöyle görünür:

POST /page.php HTTP/1.1

key1=value1&key2=value2&key3=value3

Ancak Ajax ile çok çalışıyorsanız, bu probaby aynı zamanda türler (string, int, bool) ve yapılarla (diziler, nesneler) daha karmaşık veri alışverişini de içerir, bu nedenle çoğu durumda JSON en iyi seçimdir. Ancak bir JSON yükü olan bir istek şöyle görünecektir:

POST /page.php HTTP/1.1

{"key1":"value1","key2":"value2","key3":"value3"}

İçerik şimdi application/json(veya yukarıda belirtilenlerin en azından hiçbiri) $_POSTolmayacağından, PHP'nin -wrapper'ı bununla nasıl başa çıkacağını bilmiyor (henüz).

Veriler hala orada, sadece sarmalayıcıdan erişemiyorsunuz. Bu nedenle, ham kodda kendiniz almanız gerekir file_get_contents('php://input')( kodlanmamış olduğu sürecemultipart/form-data ).

XML verilerine veya standart olmayan başka bir içerik türüne de bu şekilde erişirsiniz.


40
+1 "XML verilerine veya diğer standart olmayan içerik türlerine de bu şekilde
erişeceksiniz

@Quasdank Android uygulamasından bulutta php xampp sunucusuna JSON gönderiyorum ( stackoverflow.com/questions/36558261/… ) ancak file_get_contents ('php: // input') komutunu denediğimde çalışamadım, sadece dize (0) döndürür. Bu, yerel makinemde çalışıyordu, ancak buluta dağıtıldığında çalışmıyor. Bana yardım edebilir misiniz, lütfen?
The_Martian

1
PHP'ye AJAX isteğinde XMLHttpRequest nesnesinin kullanımının, kişinin JSON yayınlaması gerektiği anlamına gelmediğini belirtmek gerekir. Ekstra bir yüktür, ancak istemci tarafı JavaScript'iniz uygulama / x-www-form-urlencoded biçimine dönüşebilir. Ancak, çeviri veri tipi saf olmayabilir .
Anthony Rutledge

Tanınan iki içerik türünün sınırının büyük ölçüde tarihsel olduğunu söylemek gerekir. Hiçbir şey PHP'nin dizi application/jsoniçin geçerli veri kaynağı olarak tanınmasını engellemez $_POST. Ve özellikle bu destek için yayınlanmış talepler bile var.
20'de AnrDaemon


53

php://inputsize verilerin ham baytlarını verebilir. POSTed verileri genellikle AJAX POST isteği için geçerli olan JSON kodlu bir yapı ise yararlıdır.

İşte bunu yapmak için bir işlev:

  /**
   * Returns the JSON encoded POST data, if any, as an object.
   * 
   * @return Object|null
   */
  private function retrieveJsonPostData()
  {
    // get the raw POST data
    $rawData = file_get_contents("php://input");

    // this returns null if not valid json
    return json_decode($rawData);
  }

$_POSTGeleneksel POST tarafından sunulan bir form, anahtar-değer verilerini ele yaparken dizi daha kullanışlıdır. Bu yalnızca POSTed verileri genellikle tanınan bir formattaysa çalışır application/x-www-form-urlencoded( ayrıntılar için bkz. Http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4 ).


7
trueİkinci parametre olarak geçerseniz json_decode, ilişkilendirilebilir bir dizi döndüreceğini belirtmek gerekir.
Vahid Amiri

28

Kayıt verileri hatalı biçimlendirilirse, $ _POST hiçbir şey içermez. Ancak, php: // input hatalı biçimlendirilmiş dizeye sahip olacaktır.

Örneğin, bir dosyayı yüklemek için doğru anahtar / değer çifti sırası oluşturmayan ve sadece değişken adları veya herhangi bir şey olmadan tüm verileri gönderi verisi olarak dökmeyen bazı ajax uygulamaları vardır. $ _POST boş, $ _FILES boş olacak ve php: // girişinde dize olarak yazılan tam dosya bulunacaktır.


22

İlk olarak, PHP hakkında temel bir gerçek.

PHP açıkça HTTP isteklerini işlemek için saf bir REST (GET, POST, PUT, PATCH, DELETE) benzeri bir arayüz vermek üzere tasarlanmamıştır .

Ancak $_POST, $_GETve $_FILES superglobals ve işlev filter_input_array()ortalama kişinin / meslekten olmayan ihtiyaçları için çok yararlıdır.

$_POST(Ve $_GET) 'nin bir numaralı gizli avantajı, giriş verilerinizin PHP tarafından otomatik olarak urldecode edilmiş olmasıdır . Bunu yapmak zorunda kalmayı bile düşünmüyorsunuz, özellikle de standart bir GET isteği içindeki sorgu dizesi parametreleri için.

Ancak, daha fazla bilgi edinebilirsiniz ...

Bununla birlikte, programlama bilginiz ilerledikçe ve JavaScript'in XmlHttpRequestnesnesini (bazıları için jQuery) kullanmak istediğinizde , bu şemanın sınırlamasını görmeye gelirsiniz.

$_POSTsizi HTTP Content-Typeüstbilgisinde iki ortam türünün kullanımı ile sınırlar :

  1. application/x-www-form-urlencoded, ve
  2. multipart/form-data

Bu nedenle, sunucudaki PHP'ye veri değerleri göndermek ve $_POSTsüper küreselde görünmesini istiyorsanız , istemci tarafında urlencode ve adı geçen verileri anahtar / değer çiftleri olarak göndermelisiniz - acemiler için rahatsız edici bir adım (özellikle URL'nin farklı bölümlerinin farklı urlencoding biçimleri gerektirip gerektirmediğini anlamaya çalışırken: normal, ham, vb.).

Tüm jQuery kullanıcıları için $.ajax()yöntem, JSON'unuzu sunucuya aktarmadan önce URL kodlamalı anahtar / değer çiftlerine dönüştürmektir. Bu davranışı ayarlayarak geçersiz kılabilirsiniz processData: false. Sadece $ .ajax () belgelerini okuyun ve Content-Type başlığında doğru ortam türünü göndermeyi unutmayın.

URL kodlaması? Ne halt!!!???

Genellikle, bir HTML formuyla normal, eşzamanlı (tüm sayfa yeniden çizildiğinde) HTTP istekleri yapıyorsanız, kullanıcı aracısı (web tarayıcısı) form verilerinizi sizin için kodlar. XmlHttpRequestNesneyi kullanarak eşzamansız bir HTTP isteği yapmak istiyorsanız , urlen kodlu bir dize biçimlendirmeli ve bu verilerin $_POSTsüper küreselde görünmesini istiyorsanız onu göndermelisiniz .

JavaScript ile ne kadar bağlantıdasınız? :-)

Bir JavaScript dizisinden veya nesnesinden urlen kodlanmış bir dizeye dönüştürmek birçok geliştiriciyi rahatsız eder ( Form Verileri gibi yeni API'lerle bile ). Sadece JSON gönderebilirler ve istemci kodunun bunu yapması daha verimli olur .

Unutmayın (wink, wink), ortalama web geliştiricisi XmlHttpRequestnesneyi doğrudan kullanmayı öğrenmez , global işlevler, dize işlevleri, dizi işlevleri ve sizin ve ben ;-) gibi düzenli ifadeler. Onlar için Urlencoding bir kabus. ;-)

PHP, ne verir?

PHP'nin sezgisel XML ve JSON işleme eksikliği birçok kişiyi kapatır. Şimdiye kadar PHP'nin bir parçası olacağını düşünürdünüz.

Pek çok medya türü (geçmişte MIME türleri)

XML, JSON ve YAML'nin hepsinin HTTP Content-Typeüstbilgisine yerleştirilebilecek medya türleri vardır .

  • application / xml
  • uygulamamızla / json
  • application / yaml (IANA'nın resmi bir tanımı bulunmamasına rağmen)

IANA tarafından kaç medya türünün (eski adıyla MIME türleri) tanımlandığına bakın.

Bakın kaç HTTP başlığı var.

php: // giriş veya büstü

php://inputAkışı kullanmak, PHP'nin dünya üzerinde zorladığı bebek bakıcılığı / el tutma seviyesini atlamanızı sağlar. :-) Büyük güç büyük sorumluluk getirir!

Şimdi, aktarılan veri değerleriyle uğraşmadan önce php://inputbirkaç şey yapmanız / yapmanız gerekir.

  1. Doğru HTTP yönteminin gösterilip gösterilmediğini belirleyin (GET, POST, PUT, PATCH, DELETE, ...)
  2. HTTP İçerik Türü üstbilgisinin aktarılıp aktarılmadığını belirleyin.
  3. İçerik Türü değerinin istenen ortam türü olup olmadığını belirleyin .
  4. Gönderilen verilerin iyi biçimlendirilmiş XML / JSON / YMAL / vb. Olup olmadığını belirleyin .
  5. Gerekirse, verileri bir PHP veri türü: dizisine veya nesnesine dönüştürün.
  6. Bu temel kontrollerden veya dönüşümlerden herhangi biri başarısız olursa, bir istisna atın !

Karakter kodlaması ne olacak?

AH, HA! Evet, uygulamanıza gönderilen veri akışının UTF-8 kodlu olmasını isteyebilirsiniz, ancak bunun olup olmadığını nasıl anlayabilirsiniz?

İki kritik sorun.

  1. Ne kadar verinin geldiğini bilmiyorsunuz php://input.
  2. Veri akışının geçerli kodlamasını kesin olarak bilmiyorsunuz.

İlk önce ne kadar olduğunu bilmeden akış verilerini ele almaya çalışacak mısınız? Bu korkunç bir fikir . Content-LengthSahte girişin boyutu konusunda rehberlik için yalnızca HTTP başlığına güvenemezsiniz, çünkü kimlik sahtekarlığı yapılabilir.

Aşağıdakilere ihtiyacınız olacak:

  1. Akış boyutu algılama algoritması.
  2. Uygulama tanımlı akış boyutu sınırları (Apache / Nginx / PHP sınırları çok geniş olabilir).

Akışın geçerli kodlamasını bilmeden akış verilerini UTF-8'e dönüştürmeye çalışacak mısınız? Nasıl? İconv akış filtresi ( iconv akış filtresi örneği ) bunun gibi bir başlangıç ​​ve bitiş kodlaması istiyor gibi görünüyor.

'convert.iconv.ISO-8859-1/UTF-8'

Dolayısıyla, vicdanlıysanız, ihtiyacınız olacak:

  1. Akış kodlama algılama algoritması.
  2. Dinamik / çalışma zamanı akış filtresi tanım algoritması (bir priori kodlamasını başlatmayı bilemeyeceğiniz için).

( Güncelleme : 'convert.iconv.UTF-8/UTF-8'her şeyi UTF-8'e zorlar, ancak hala iconv kütüphanesinin nasıl çevrileceğini bilemeyeceği karakterleri hesaba katmanız gerekir. : 1) Sahte bir karakter girin, 2) Arıza / atış ve istisna).

Content-EncodingAşağıdaki gibi sıkıştırma gibi bir şeyi gösterebileceğinden, yalnızca HTTP başlığına güvenemezsiniz . İconv ile ilgili karar vermek istemediğiniz şey bu değildir.

Content-Encoding: gzip

Bu nedenle, genel adımlar ...

Bölüm I: HTTP Talebi İle İlgili

  1. Doğru HTTP yönteminin gösterilip gösterilmediğini belirleyin (GET, POST, PUT, PATCH, DELETE, ...)
  2. HTTP İçerik Türü üstbilgisinin aktarılıp aktarılmadığını belirleyin.
  3. İçerik Türü değerinin istenen ortam türü olup olmadığını belirleyin .

Bölüm II: Akım Verileri İle İlgili

  1. Giriş akışının boyutunu belirleyin (isteğe bağlı, ancak önerilir).
  2. Giriş akışının kodlamasını belirleyin.
  3. Gerekirse, giriş akışını istenen karakter kodlamasına (UTF-8) dönüştürün.
  4. Gerekirse, uygulama düzeyinde sıkıştırma veya şifrelemeyi tersine çevirin ve ardından 4, 5 ve 6. adımları tekrarlayın.

Bölüm III: Veri Türü İle İlgili

  1. Gönderilen verilerin iyi biçimlendirilmiş XML / JSON / YMAL / vb. Olup olmadığını belirleyin .

(Verilerin yine de ayrıştırıp URL kodunu çözmeniz gereken URL kodlu bir dize olabileceğini unutmayın).

  1. Gerekirse, verileri bir PHP veri türü: dizisine veya nesnesine dönüştürün.

Bölüm IV: İlgili Veri Değeri

  1. Giriş verilerine filtre uygulayın.

  2. Giriş verilerini doğrulayın.

Şimdi görüyor musun?

$_POSTGirişi sınırları için php.ini ayarları ile birlikte süper küresel, rahip olmayan kimse için basittir. Bununla birlikte, karakter kodlaması ile uğraşmak akışları kullanırken çok daha sezgisel ve etkilidir çünkü uygun kodlama için giriş değerlerini kontrol etmek için süper küreseller (veya genellikle diziler) arasında geçiş yapmaya gerek yoktur.


1
Vay canına! Bu cevap çok daha yüksek bir derecelendirmeye sahip olmalıdır. Sel ışığını karanlığa getirdiğiniz için çok teşekkür ederim.
Lox

Son analizde, PHP temel varsayılanları güncellemek için iyi olurdu. Ancak, bir HTTP istek yöntemini aynı adda bir veri yapısıyla ($ _GET, $ _POST) birleştirmek mantıklı bir yanlıştır. Önemli olan (1) istenen HTTP istek yöntemidir ve (2) bu taleple (İçerik Tipi) istek verileri vardır. Bu nedenle, Perl'de olduğu gibi, dil yaratıcılarının / sürdürücülerinin görüşlerinin istekli kurbanı olabileceğinizi göreceksiniz.
Anthony Rutledge

0

Bu yüzden php: // input akışından POST verilerini alacak bir fonksiyon yazdım .

Bu yüzden burada zorluk PUT, DELETE OR PATCH istek yöntemine geçiyordu ve yine de bu istekle gönderilen gönderi verilerini elde ediyordu.

Bunu belki de benzer zorluklarla karşılaşan biri için paylaşıyorum. Aşağıdaki fonksiyon ben geldi ve işe yarıyor. Umut ediyorum bu yardım eder!

    /**
     * @method Post getPostData
     * @return array
     * 
     * Convert Content-Disposition to a post data
     */
    function getPostData() : array
    {
        // @var string $input
        $input = file_get_contents('php://input');

        // continue if $_POST is empty
        if (strlen($input) > 0 && count($_POST) == 0 || count($_POST) > 0) :

            $postsize = "---".sha1(strlen($input))."---";

            preg_match_all('/([-]{2,})([^\s]+)[\n|\s]{0,}/', $input, $match);

            // update input
            if (count($match) > 0) $input = preg_replace('/([-]{2,})([^\s]+)[\n|\s]{0,}/', '', $input);

            // extract the content-disposition
            preg_match_all("/(Content-Disposition: form-data; name=)+(.*)/m", $input, $matches);

            // let's get the keys
            if (count($matches) > 0 && count($matches[0]) > 0)
            {
                $keys = $matches[2];

                foreach ($keys as $index => $key) :
                    $key = trim($key);
                    $key = preg_replace('/^["]/','',$key);
                    $key = preg_replace('/["]$/','',$key);
                    $key = preg_replace('/[\s]/','',$key);
                    $keys[$index] = $key;
                endforeach;

                $input = preg_replace("/(Content-Disposition: form-data; name=)+(.*)/m", $postsize, $input);

                $input = preg_replace("/(Content-Length: )+([^\n]+)/im", '', $input);

                // now let's get key value
                $inputArr = explode($postsize, $input);

                // @var array $values
                $values = [];

                foreach ($inputArr as $index => $val) :
                    $val = preg_replace('/[\n]/','',$val);

                    if (preg_match('/[\S]/', $val)) $values[$index] = trim($val);

                endforeach;

                // now combine the key to the values
                $post = [];

                // @var array $value
                $value = [];

                // update value
                foreach ($values as $i => $val) $value[] = $val;

                // push to post
                foreach ($keys as $x => $key) $post[$key] = isset($value[$x]) ? $value[$x] : '';

                if (is_array($post)) :

                    $newPost = [];

                    foreach ($post as $key => $val) :

                        if (preg_match('/[\[]/', $key)) :

                            $k = substr($key, 0, strpos($key, '['));
                            $child = substr($key, strpos($key, '['));
                            $child = preg_replace('/[\[|\]]/','', $child);
                            $newPost[$k][$child] = $val;

                        else:

                            $newPost[$key] = $val;

                        endif;

                    endforeach;

                    $_POST = count($newPost) > 0 ? $newPost : $post;

                endif;
            }

        endif;

        // return post array
        return $_POST;
    }

-5

Nasıl kullanılacağına dair basit bir örnek

 <?php  
     if(!isset($_POST) || empty($_POST)) { 
     ?> 
        <form name="form1" method="post" action=""> 
          <input type="text" name="textfield"><br /> 
          <input type="submit" name="Submit" value="submit"> 
        </form> 
   <?php  
        } else { 
        $example = file_get_contents("php://input");
        echo $example;  }  
   ?>
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.