Helpex - Trao đổi & giúp đỡ Đăng nhập
505

Khi nào bạn sẽ xem xét sử dụng cái này hơn cái kia và tại sao?

505 hữu ích 3 bình luận 395k xem chia sẻ
747

Cái HTTP_HOSTđược lấy từ tiêu đề yêu cầu HTTP và đây là thứ mà máy khách thực sự sử dụng làm "máy chủ đích" của yêu cầu. Các SERVER_NAMEđịnh nghĩa trong cấu hình máy chủ. Cái nào để sử dụng phụ thuộc vào những gì bạn cần nó cho. Tuy nhiên, bây giờ bạn nên nhận ra rằng giá trị này là giá trị do khách hàng kiểm soát, do đó có thể không đáng tin cậy để sử dụng trong logic nghiệp vụ và giá trị kia là giá trị do máy chủ kiểm soát, đáng tin cậy hơn. Tuy nhiên, bạn cần đảm bảo rằng máy chủ web đang đề cập có SERVER_NAMEcấu hình chính xác. Lấy Apache HTTPD làm ví dụ, đây là một trích xuất từ tài liệu của nó :

Nếu không ServerNameđược chỉ định, thì máy chủ sẽ cố gắng suy ra tên máy chủ bằng cách thực hiện tra cứu ngược lại trên địa chỉ IP. Nếu không có cổng nào được chỉ định trong ServerNamethì máy chủ sẽ sử dụng cổng từ yêu cầu đến. Để có độ tin cậy và dự đoán tối ưu, bạn nên chỉ định tên máy chủ và cổng rõ ràng bằng cách sử dụng lệnh ServerName.


Cập nhật : sau khi kiểm tra câu trả lời của Pekka về câu hỏi của bạn có liên kết đến câu trả lời của bobince rằng PHP sẽ luôn trả về HTTP_HOSTgiá trị của SERVER_NAMEnó, đi ngược lại với trải nghiệm PHP 4.x + Apache HTTPD 1.2.x của tôi từ vài năm trước , Tôi đã thổi bụi từ môi trường XAMPP hiện tại của mình trên Windows XP (Apache HTTPD 2.2.1 với PHP 5.2.8), đã khởi động nó, tạo một trang PHP in cả hai giá trị, tạo một ứng dụng thử nghiệm Java bằng cách URLConnectionsửa đổi Hosttiêu đề và các xét nghiệm đã dạy tôi rằng đây thực sự là (không chính xác) trường hợp.

Sau lần đầu tiên nghi ngờ PHP và đào một số báo cáo lỗi PHP liên quan đến chủ đề này, tôi đã biết rằng gốc rễ của vấn đề là ở máy chủ web được sử dụng, rằng nó trả lại Hosttiêu đề HTTP không chính xác khi SERVER_NAMEđược yêu cầu. Vì vậy, tôi đã tìm hiểu các báo cáo lỗi HTTPD bằng cách sử dụng các từ khóa khác nhau liên quan đến chủ đề và cuối cùng tôi đã tìm thấy một lỗi liên quan . Hành vi này đã được giới thiệu từ khoảng Apache HTTPD 1.3. Bạn cần phải thiết lập UseCanonicalNamechỉ để ontrong <VirtualHost>entry của ServerNametrong httpd.conf(cũng kiểm tra các cảnh báo ở dưới cùng của tài liệu !).

<VirtualHost *>
    ServerName example.com
    UseCanonicalName on
</VirtualHost> 

Điều này làm việc cho tôi.

Tóm tắt, SERVER_NAMEđáng tin cậy hơn, nhưng bạn phụ thuộc vào cấu hình máy chủ!

747 hữu ích 5 bình luận chia sẻ
63

HTTP_HOSTlà máy chủ đích được gửi bởi khách hàng. Nó có thể được thao tác tự do bởi người dùng. Không có vấn đề gì để gửi yêu cầu đến trang web của bạn yêu cầu HTTP_HOSTgiá trị www.stackoverflow.com.

SERVER_NAMExuất phát từ VirtualHostđịnh nghĩa của máy chủ và do đó được coi là đáng tin cậy hơn. Tuy nhiên, nó cũng có thể bị thao túng từ bên ngoài trong một số điều kiện nhất định liên quan đến cách thiết lập máy chủ web của bạn: Xem câu hỏi SO này liên quan đến các khía cạnh bảo mật của cả hai biến thể.

Bạn không nên dựa vào một trong hai để được an toàn. Điều đó nói rằng, những gì để sử dụng thực sự phụ thuộc vào những gì bạn muốn làm. Nếu bạn muốn xác định miền nào tập lệnh của bạn đang chạy, bạn có thể sử dụng một cách an toàn HTTP_HOSTmiễn là các giá trị không hợp lệ đến từ người dùng độc hại không thể phá vỡ bất cứ điều gì.

63 hữu ích 5 bình luận chia sẻ
51

Như tôi đã đề cập trong câu trả lời này , nếu máy chủ chạy trên một cổng khác 80 (như có thể phổ biến trên máy phát triển / mạng nội bộ) thì HTTP_HOSTcó chứa cổng, trong khi SERVER_NAMEkhông.

$_SERVER['HTTP_HOST'] == 'localhost:8080'
$_SERVER['SERVER_NAME'] == 'localhost'

(Ít nhất đó là những gì tôi đã nhận thấy trong các máy chủ ảo dựa trên cổng Apache)

Lưu ý rằng HTTP_HOSTkhông không chứa :443khi chạy trên HTTPS (trừ khi bạn đang chạy trên một cổng không chuẩn, mà tôi đã không kiểm tra).

Như những người khác đã lưu ý, cả hai cũng khác nhau khi sử dụng IPv6:

$_SERVER['HTTP_HOST'] == '[::1]'
$_SERVER['SERVER_NAME'] == '::1'
51 hữu ích 1 bình luận chia sẻ
26

Xin lưu ý rằng nếu bạn muốn sử dụng IPv6, có lẽ bạn muốn sử dụng HTTP_HOSThơn là SERVER_NAME. Nếu bạn nhập http://[::1]/các biến môi trường sẽ như sau:

HTTP_HOST = [::1]
SERVER_NAME = ::1

Điều này có nghĩa là, nếu bạn làm một mod_rewrite chẳng hạn, bạn có thể nhận được một kết quả khó chịu. Ví dụ cho chuyển hướng SSL:

# SERVER_NAME will NOT work - Redirection to https://::1/
RewriteRule .* https://%{SERVER_NAME}/

# HTTP_HOST will work - Redirection to https://[::1]/
RewriteRule .* https://%{HTTP_HOST}/

Điều này chỉ áp dụng nếu bạn truy cập máy chủ mà không có tên máy chủ.

26 hữu ích 1 bình luận chia sẻ
6

nếu bạn muốn kiểm tra thông qua server.php hoặc những gì bạn muốn gọi nó bằng cách sau:

<?php

phpinfo(INFO_VARIABLES);

?>

hoặc là

<?php

header("Content-type: text/plain");

print_r($_SERVER);

?>

Sau đó truy cập nó với tất cả các url hợp lệ cho trang web của bạn và kiểm tra sự khác biệt.

6 hữu ích 0 bình luận chia sẻ
4

Phụ thuộc vào những gì tôi muốn tìm hiểu. SERVER_NAME là tên máy chủ của máy chủ, trong khi HTTP_HOST là máy chủ ảo mà máy khách được kết nối.

4 hữu ích 3 bình luận chia sẻ
2

Phải mất một thời gian tôi mới hiểu mọi người có nghĩa là ' SERVER_NAMEđáng tin cậy hơn'. Tôi sử dụng một máy chủ được chia sẻ và không có quyền truy cập vào các chỉ thị máy chủ ảo. Vì vậy, tôi sử dụng mod_rewrite .htaccess để ánh xạ các HTTP_HOSTs khác nhau vào các thư mục khác nhau. Trong trường hợp đó, nó HTTP_HOSTcó ý nghĩa.

Tình huống tương tự nếu một người sử dụng máy chủ ảo dựa trên tên: lệnh ServerNametrong máy chủ ảo chỉ đơn giản nói tên máy chủ nào sẽ được ánh xạ tới máy chủ ảo này. Điểm mấu chốt là, trong cả hai trường hợp, tên máy chủ được cung cấp bởi máy khách trong yêu cầu ( HTTP_HOST), phải được khớp với một tên trong máy chủ, chính nó được ánh xạ tới một thư mục. Việc ánh xạ được thực hiện với các chỉ thị máy chủ ảo hay với các quy tắc mod_rewrite của htaccess là thứ yếu ở đây. Trong những trường hợp này, HTTP_HOSTsẽ giống như SERVER_NAME. Tôi vui vì Apache được cấu hình theo cách đó.

Tuy nhiên, tình hình là khác nhau với các máy chủ ảo dựa trên IP. Trong trường hợp này và chỉ trong trường hợp này, SERVER_NAMEHTTP_HOSTcó thể khác, bởi vì bây giờ máy khách chọn máy chủ theo IP, không phải theo tên. Thật vậy, có thể có cấu hình đặc biệt trong đó điều này là quan trọng.

Vì vậy, bắt đầu từ bây giờ, tôi sẽ sử dụng SERVER_NAME, chỉ trong trường hợp mã của tôi được chuyển trong các cấu hình đặc biệt này.

2 hữu ích 0 bình luận chia sẻ
2

Giả sử một người có một thiết lập đơn giản (CentOS 7, Apache 2.4.x và PHP 5.6.20) và chỉ có một trang web (không giả sử lưu trữ ảo) ...

Theo nghĩa của PHP, $_SERVER['SERVER_NAME']là một phần tử mà các thanh ghi PHP trong siêu lớp $_SERVERdựa trên cấu hình Apache của bạn ( **ServerName**chỉ thị với UseCanonicalName On) trong httpd.conf (có thể là từ tệp cấu hình máy chủ ảo đi kèm, bất cứ điều gì, v.v.). HTTP_HOST có nguồn gốc từ hosttiêu đề HTTP . Coi đây là đầu vào của người dùng Lọc và xác nhận trước khi sử dụng.

Dưới đây là một ví dụ về nơi tôi sử dụng $_SERVER['SERVER_NAME']làm cơ sở để so sánh. Phương pháp sau đây là từ một lớp con cụ thể mà tôi đã đặt tên ServerValidator(con của Validator). ServerValidatorkiểm tra sáu hoặc bảy yếu tố trong $ _SERVER trước khi sử dụng chúng.

Để xác định xem yêu cầu HTTP có phải là POST không, tôi sử dụng phương thức này.

public function isPOST()
{
    return (($this->requestMethod === 'POST')    &&  // Ignore
            $this->hasTokenTimeLeft()            &&  // Ignore
            $this->hasSameGETandPOSTIdentities() &&  // Ingore
            ($this->httpHost === filter_input(INPUT_SERVER, 'SERVER_NAME')));
}

Vào thời điểm phương thức này được gọi, tất cả việc lọc và xác thực các phần tử $ _SERVER có liên quan sẽ xảy ra (và các thuộc tính có liên quan được đặt).

Dòng ...

($this->httpHost === filter_input(INPUT_SERVER, 'SERVER_NAME')

... Kiểm tra xem $_SERVER['HTTP_HOST']giá trị (cuối cùng xuất phát từ hosttiêu đề HTTP được yêu cầu ) khớp với $_SERVER['SERVER_NAME'].

Bây giờ, tôi đang sử dụng speak superglobal để giải thích ví dụ của tôi, nhưng đó chỉ là vì một số người không quen với INPUT_GET, INPUT_POSTINPUT_SERVERliên quan đến filter_input_array().

Điểm mấu chốt là, tôi không xử lý các yêu cầu POST trên máy chủ của mình trừ khi tất cả bốn điều kiện được đáp ứng. Do đó, về mặt yêu cầu POST, thất bại trong việc cung cấp một HTTP hostheader (hiện diện kiểm tra trước đó) sẽ làm rõ số phận cho nghiêm ngặt HTTP 1.0 trình duyệt. Hơn nữa, các máy chủ yêu cầu phải phù hợp với giá trị cho ServerNametrong httpd.conf , và, bằng cách gia hạn, giá trị cho $_SERVER('SERVER_NAME')trong $_SERVERsuperglobal. Một lần nữa, tôi sẽ sử dụng INPUT_SERVERvới các hàm bộ lọc PHP, nhưng bạn bắt được sự trôi dạt của tôi.

Hãy nhớ rằng Apache thường xuyên sử dụng ServerNametrong các chuyển hướng tiêu chuẩn (chẳng hạn như bỏ dấu gạch chéo ra khỏi URL: Ví dụ: http://www.foo.com trở thành http://www.foo.com/ ), ngay cả khi bạn không sử dụng viết lại URL.

Tôi sử dụng $_SERVER['SERVER_NAME']như là tiêu chuẩn, không $_SERVER['HTTP_HOST']. Có rất nhiều vấn đề qua lại về vấn đề này. $_SERVER['HTTP_HOST']có thể trống, vì vậy đây không phải là cơ sở để tạo các quy ước mã như phương thức công khai của tôi ở trên. Nhưng, chỉ vì cả hai có thể được đặt không đảm bảo chúng sẽ bằng nhau. Kiểm tra là cách tốt nhất để biết chắc chắn (ghi nhớ phiên bản Apache và phiên bản PHP).

2 hữu ích 0 bình luận chia sẻ
0

Như balusC cho biết SERVER_NAME không đáng tin cậy và có thể được thay đổi trong cấu hình apache, cấu hình tên máy chủ của máy chủ và tường lửa có thể nằm giữa bạn và máy chủ.

Chức năng theo sau luôn trả về máy chủ thực (máy chủ đã gõ) mà không có cổng và nó gần như đáng tin cậy:

function getRealHost(){
   list($realHost,)=explode(':',$_SERVER['HTTP_HOST']);
   return $realHost;
}
0 hữu ích 0 bình luận chia sẻ
loading
Không tìm thấy câu trả lời bạn tìm kiếm? Duyệt qua các câu hỏi được gắn thẻ php apache server-variables , hoặc hỏi câu hỏi của bạn.

Có thể bạn quan tâm

loading