PHP $ _SERVER ['HTTP_HOST'] so với $ _SERVER ['SERVER_NAME'], tôi có hiểu chính xác các trang man không?


167

Tôi đã tìm kiếm rất nhiều và cũng đọc các tài liệu PHP $ _SERVER . Tôi có quyền này về việc sử dụng tập lệnh PHP nào cho các định nghĩa liên kết đơn giản được sử dụng trên toàn trang web của tôi không?

$_SERVER['SERVER_NAME'] được dựa trên tệp cấu hình của máy chủ web của bạn (Apache2 trong trường hợp của tôi) và thay đổi tùy thuộc vào một số chỉ thị: (1) Virtualhost, (2) ServerName, (3) UseCanonicalName, v.v.

$_SERVER['HTTP_HOST'] được dựa trên yêu cầu từ khách hàng.

Do đó, dường như đối với tôi, một cách thích hợp để sử dụng để làm cho các kịch bản của tôi tương thích nhất có thể $_SERVER['HTTP_HOST']. Giả định này có đúng không?

Theo dõi ý kiến:

Tôi đoán rằng tôi đã có một chút hoang tưởng sau khi đọc bài viết này và lưu ý rằng một số người nói rằng "họ sẽ không tin bất kỳ ai trong số các $_SERVERvars":

Rõ ràng cuộc thảo luận chủ yếu là về $_SERVER['PHP_SELF']và tại sao bạn không nên sử dụng nó trong thuộc tính hành động biểu mẫu mà không thoát ra thích hợp để ngăn chặn các cuộc tấn công XSS.

Kết luận của tôi về câu hỏi ban đầu của tôi ở trên là "an toàn" khi sử dụng $_SERVER['HTTP_HOST']cho tất cả các liên kết trên một trang web mà không phải lo lắng về các cuộc tấn công XSS, ngay cả khi được sử dụng trong các biểu mẫu.

Vui long sửa cho tôi nêu tôi sai.

Câu trả lời:


149

Đó có lẽ là suy nghĩ đầu tiên của mọi người. Nhưng nó khó hơn một chút. Xem bài viết của Chris Shiflett SERVER_NAMEVersusHTTP_HOST .

Dường như không có viên đạn bạc. Chỉ khi bạn buộc Apache sử dụng tên chính tắc, bạn sẽ luôn có được tên máy chủ phù hợp SERVER_NAME.

Vì vậy, bạn có thể đi với điều đó hoặc bạn kiểm tra tên máy chủ trong danh sách trắng:

$allowed_hosts = array('foo.example.com', 'bar.example.com');
if (!isset($_SERVER['HTTP_HOST']) || !in_array($_SERVER['HTTP_HOST'], $allowed_hosts)) {
    header($_SERVER['SERVER_PROTOCOL'].' 400 Bad Request');
    exit;
}

4
Lol, tôi đã đọc bài báo đó và nó dường như không thực sự trả lời câu hỏi của tôi. Cái nào làm pro dev sử dụng? Nếu một trong hai.
Jeff

2
Thật thú vị, tôi chưa bao giờ biết SERVER_NAME đã sử dụng các giá trị do người dùng cung cấp theo mặc định trong Apache.
Powerlord

1
@Jeff, Đối với các máy chủ lưu trữ nhiều hơn một tên miền phụ, bạn chỉ có hai lựa chọn $_SERVER['SERVER_NAME']$_SERVER['HTTP_HOST'](ngoài việc thực hiện một số bắt tay tùy chỉnh khác dựa trên yêu cầu của người dùng). Các nhà phát triển chuyên nghiệp không tin tưởng vào những điều họ không hiểu hoàn toàn. Vì vậy, họ có thiết lập SAPI hoàn toàn chính xác (trong trường hợp tùy chọn họ sử dụng sẽ cho kết quả chính xác) hoặc họ sẽ đưa vào danh sách trắng sao cho việc cung cấp SAPI không quan trọng.
Pacerier

@Gumbo, Bạn cần áp dụng bản vá "cổng" do các vấn đề nghiêm trọng với một số SAPI nhất định. Ngoài ra, array_key_existskhả năng mở rộng hơn so với in_arraycó hiệu suất O (n).
Pacerier

2
@Pacerier mảng_key_exists và in_array làm những việc khác nhau, kiểm tra trước cho khóa, giá trị sau, vì vậy bạn không thể trao đổi chúng. Ngoài ra, nếu bạn có một mảng gồm hai giá trị, bạn thực sự không nên lo lắng về hiệu suất O (n) ...
eis

74

Chỉ cần một lưu ý bổ sung - 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)

Như Mike đã lưu ý dưới đây, 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).


4
Lưu ý: Cổng không có trong HTTP_HOST cho 443 (cổng SSL mặc định).
Mike

Vì vậy, nói cách khác, giá trị của HTTP_HOSTkhông chính xác là Host:tham số mà người dùng cung cấp. Nó chỉ đơn thuần dựa trên điều đó.
Pacerier

1
@Pacerier Không, điều này ngược lại: HTTP_HOST chính xác là trường Host: được cung cấp với yêu cầu HTTP. Cổng này là một phần của nó và các trình duyệt không đề cập đến nó khi nó là cổng mặc định (80 cho HTTP; 443 cho HTTPS)
xhienne

29

Sử dụng. Cả hai đều an toàn (trong) như nhau, vì trong nhiều trường hợp, SERVER_NAME chỉ được điền từ HTTP_HOST. Tôi thường sử dụng HTTP_HOST để người dùng giữ nguyên tên máy chủ chính xác mà họ đã bắt đầu. Ví dụ: nếu tôi có cùng một trang web trên một tên miền .com và .org, tôi không muốn gửi ai đó từ .org đến .com, đặc biệt nếu họ có thể có mã thông báo đăng nhập trên .org mà họ sẽ mất nếu được gửi đến tên miền khác.

Dù bằng cách nào, bạn chỉ cần chắc chắn rằng ứng dụng web của bạn sẽ chỉ phản hồi cho các tên miền tốt. Điều này có thể được thực hiện bằng (a) với kiểm tra phía ứng dụng như Gumbo's hoặc (b) bằng cách sử dụng máy chủ ảo trên (các) tên miền mà bạn muốn không đáp ứng với các yêu cầu cung cấp tiêu đề Máy chủ không xác định.

Lý do cho điều này là vì nếu bạn cho phép trang web của bạn được truy cập dưới bất kỳ tên cũ nào, bạn sẽ tự mở các cuộc tấn công đảo ngược DNS (nơi tên máy chủ của một trang web khác trỏ đến IP của bạn, người dùng truy cập trang web của bạn bằng tên máy chủ của kẻ tấn công, sau đó là tên máy chủ được chuyển đến IP của kẻ tấn công, lấy cookie / auth của bạn) và chiếm quyền điều khiển công cụ tìm kiếm (nơi kẻ tấn công trỏ tên máy chủ của chúng vào trang web của bạn và cố gắng làm cho các công cụ tìm kiếm xem đó là tên máy chủ chính 'tốt nhất').

Rõ ràng cuộc thảo luận chủ yếu là về $ _SERVER ['PHP_SELF'] và tại sao bạn không nên sử dụng nó trong thuộc tính hành động biểu mẫu mà không thoát thích hợp để ngăn chặn các cuộc tấn công XSS.

Pfft. Chà, bạn không nên sử dụng bất cứ thứ gì trong bất kỳ thuộc tính nào mà không thoát ra htmlspecialchars($string, ENT_QUOTES), vì vậy không có gì đặc biệt về các biến máy chủ ở đó.


Ở lại với giải pháp (a), (b) không thực sự an toàn, sử dụng URI tuyệt đối trong các yêu cầu HTTP cho phép bỏ qua bảo mật virtualhosts dựa trên tên. Vì vậy, quy tắc thực sự là không bao giờ tin tưởng SERVER_NAME hoặc HTTP_HOST.
regilero

@bobince, công cụ tìm kiếm chiếm quyền điều khiển hoạt động như thế nào? Các công cụ tìm kiếm ánh xạ các từ đến các url tên miền , chúng không xử lý IP. Vậy tại sao bạn nói rằng "kẻ tấn công có thể khiến các công cụ tìm kiếm xem attacker.comlà nguồn chính tốt nhất cho IP máy chủ của bạn" nghĩa là gì? Điều đó dường như không có ý nghĩa gì với các công cụ tìm kiếm, thậm chí điều đó sẽ làm gì?
Pacerier

2
Google chắc chắn có (và có lẽ vẫn còn trong một số hình thức) các khái niệm về các trang web lừa bịp, do đó nếu trang web của bạn có thể truy cập như http://example.com/, http://www.example.com/http://93.184.216.34/nó sẽ kết hợp chúng thành một trang web, chọn phổ biến nhất trong các địa chỉ, và chỉ trả lại các liên kết đến đó phiên bản. Nếu bạn có thể trỏ evil-example.comđến cùng một địa chỉ và làm cho Google thấy ngắn gọn rằng đó là địa chỉ phổ biến hơn bạn có thể ăn cắp nước trái cây của trang web. Tôi không biết thực tế ngày nay như thế nào nhưng tôi đã thấy những kẻ tấn công trang trại liên kết của Nga cố gắng làm điều đó trong quá khứ.
bobince

24

Đây là bản dịch dài dòng về những gì Symfony sử dụng để lấy tên máy chủ ( xem ví dụ thứ hai để có bản dịch đúng nghĩa hơn ):

function getHost() {
    $possibleHostSources = array('HTTP_X_FORWARDED_HOST', 'HTTP_HOST', 'SERVER_NAME', 'SERVER_ADDR');
    $sourceTransformations = array(
        "HTTP_X_FORWARDED_HOST" => function($value) {
            $elements = explode(',', $value);
            return trim(end($elements));
        }
    );
    $host = '';
    foreach ($possibleHostSources as $source)
    {
        if (!empty($host)) break;
        if (empty($_SERVER[$source])) continue;
        $host = $_SERVER[$source];
        if (array_key_exists($source, $sourceTransformations))
        {
            $host = $sourceTransformations[$source]($host);
        } 
    }

    // Remove port number from host
    $host = preg_replace('/:\d+$/', '', $host);

    return trim($host);
}

Đã lỗi thời:

Đây là bản dịch của tôi sang PHP trần trụi của một phương thức được sử dụng trong khung Symfony cố lấy tên máy chủ từ mọi cách có thể theo thứ tự thực hành tốt nhất:

function get_host() {
    if ($host = $_SERVER['HTTP_X_FORWARDED_HOST'])
    {
        $elements = explode(',', $host);

        $host = trim(end($elements));
    }
    else
    {
        if (!$host = $_SERVER['HTTP_HOST'])
        {
            if (!$host = $_SERVER['SERVER_NAME'])
            {
                $host = !empty($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR'] : '';
            }
        }
    }

    // Remove port number from host
    $host = preg_replace('/:\d+$/', '', $host);

    return trim($host);
}

1
@StefanNch Vui lòng xác định "cách này".
showdev

1
@showdev Tôi thực sự thấy "khó" khi đọc câu lệnh điều kiện như if ($host = $_SERVER['HTTP_X_FORWARDED_HOST'])hay x = a == 1 ? True : False. Lần đầu tiên tôi thấy nó, bộ não của tôi đang tìm kiếm khởi tạo $ host và một câu trả lời cho "tại sao chỉ có một dấu" = "?". Tôi bắt đầu không thích ngôn ngữ lập trình gõ yếu. Mọi thứ được viết khác nhau. Bạn không tiết kiệm thời gian và bạn không đặc biệt. Tôi không viết mã theo cách này, vì sau khi thời gian trôi qua, tôi là người cần gỡ lỗi. Trông thật bừa bộn cho một bộ não mệt mỏi! Tôi biết tiếng Anh của tôi là tiếng Anh, nhưng ít nhất tôi cũng cố gắng.
StefanNch

1
Các bạn, tôi chỉ đơn giản là chuyển mã từ Symfony. Đây là cách tôi đã thực hiện nó. Đối với tất cả những gì nó quan trọng - nó hoạt động và nó có vẻ khá kỹ lưỡng. Bản thân tôi cũng vậy, điều này không đủ để đọc nhưng tôi không có thời gian để viết lại hoàn toàn.
chống độc

2
Trông ổn với tôi. Đó là các toán tử ternary và thực sự có thể tiết kiệm thời gian (và byte) mà không làm giảm khả năng đọc, khi được sử dụng một cách thích hợp.
showdev

1
@antitoxic, -1 Các lập trình viên Symfony (giống như nhiều người khác) không biết chính xác họ đang làm gì trong trường hợp này. Điều này không cung cấp cho bạn tên máy chủ (xem câu trả lời của Simon). Đây chỉ đơn thuần là cung cấp cho bạn một tốt nhất đoán đó sẽ là sai nhiều lần.
Pacerier

11

Có an toàn không khi sử dụng $_SERVER['HTTP_HOST']cho tất cả các liên kết trên một trang web mà không phải lo lắng về các cuộc tấn công XSS, ngay cả khi được sử dụng trong các biểu mẫu?

Có, nó an toàn để sử dụng $_SERVER['HTTP_HOST'], (và thậm chí $_GET$_POST) miễn là bạn xác minh chúng trước khi chấp nhận chúng. Đây là những gì tôi làm cho các máy chủ sản xuất an toàn:

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
$reject_request = true;
if(array_key_exists('HTTP_HOST', $_SERVER)){
    $host_name = $_SERVER['HTTP_HOST'];
    // [ need to cater for `host:port` since some "buggy" SAPI(s) have been known to return the port too, see http://goo.gl/bFrbCO
    $strpos = strpos($host_name, ':');
    if($strpos !== false){
        $host_name = substr($host_name, $strpos);
    }
    // ]
    // [ for dynamic verification, replace this chunk with db/file/curl queries
    $reject_request = !array_key_exists($host_name, array(
        'a.com' => null,
        'a.a.com' => null,
        'b.com' => null,
        'b.b.com' => null
    ));
    // ]
}
if($reject_request){
    // log errors
    // display errors (optional)
    exit;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
echo 'Hello World!';
// ...

Ưu điểm $_SERVER['HTTP_HOST']là hành vi của nó được xác định rõ hơn $_SERVER['SERVER_NAME']. Ngược ➫➫ :

Nội dung của Máy chủ: tiêu đề từ yêu cầu hiện tại, nếu có.

với:

Tên của máy chủ lưu trữ theo đó tập lệnh hiện tại đang thực thi.

Sử dụng một giao diện được xác định tốt hơn như $_SERVER['HTTP_HOST']có nghĩa là nhiều SAPI sẽ triển khai nó bằng cách sử dụng hành vi được xác định rõ ràng đáng tin cậy . (Không giống như cái khác .) Tuy nhiên, nó vẫn hoàn toàn phụ thuộc vào SAPI ➫➫ :

Không có gì đảm bảo rằng mọi máy chủ web sẽ cung cấp bất kỳ [ $_SERVERmục] nào; máy chủ có thể bỏ qua một số hoặc cung cấp những cái khác không được liệt kê ở đây.

Để hiểu cách lấy đúng tên máy chủ, trước hết, bạn cần hiểu rằng một máy chủ chỉ chứa không có phương tiện để biết (điều kiện tiên quyết để xác minh) tên riêng của nó trên mạng. Nó cần phải giao diện với một thành phần cung cấp cho nó tên riêng của nó. Điều này có thể được thực hiện thông qua:

  • tập tin cấu hình cục bộ

  • cơ sở dữ liệu địa phương

  • mã nguồn cứng

  • yêu cầu bên ngoài ( curl )

  • Host:yêu cầu khách hàng / kẻ tấn công

  • Vân vân

Thông thường nó được thực hiện thông qua tập tin cấu hình cục bộ (SAPI). Lưu ý rằng bạn đã cấu hình nó một cách chính xác, ví dụ như trong Apache ➫➫ :

Một vài điều cần phải được 'làm giả' để làm cho máy chủ ảo động trông giống như một máy chủ bình thường.

Điều quan trọng nhất là tên máy chủ được Apache sử dụng để tạo các URL tự tham chiếu, v.v. Nó được cấu hình bằng lệnh ServerNamevà nó có sẵn cho CGI thông qua SERVER_NAMEbiến môi trường.

Giá trị thực được sử dụng trong thời gian chạy được kiểm soát bởi cài đặt UseCanonicalName.

Với UseCanonicalName Off tên máy chủ xuất phát từ nội dung của Host:tiêu đề trong yêu cầu. Với UseCanonicalName DNS nó đến từ một tra cứu DNS ngược của địa chỉ IP của máy chủ ảo. Cài đặt trước được sử dụng cho lưu trữ ảo động dựa trên tên và cài đặt sau được sử dụng cho ** lưu trữ dựa trên IP.

Nếu Apache không thể tìm ra tên máy chủ vì không có Host:tiêu đề hoặc tra cứu DNS không thành công thì giá trị được cấu hình ServerNamesẽ được sử dụng thay thế.


8

Sự khác biệt chính giữa hai là $_SERVER['SERVER_NAME']một biến do máy chủ kiểm soát, trong khi đó $_SERVER['HTTP_HOST']là giá trị do người dùng kiểm soát.

Nguyên tắc chung là không bao giờ tin tưởng các giá trị từ người dùng, do đó, $_SERVER['SERVER_NAME']là sự lựa chọn tốt hơn.

Như Gumbo đã chỉ ra, Apache sẽ xây dựng SERVER_NAME từ các giá trị do người dùng cung cấp nếu bạn không đặt UseCanonicalName On.

Chỉnh sửa: Đã nói tất cả, nếu trang web đang sử dụng máy chủ ảo dựa trên tên, tiêu đề Máy chủ HTTP là cách duy nhất để truy cập các trang web không phải là trang web mặc định.


Hiểu. Hangout của tôi là "làm thế nào người dùng có thể thay đổi giá trị của $ _SERVER ['HTTP_HOST']?" Nó thậm chí có thể?
Jeff

5
Người dùng có thể thay đổi điều đó bởi vì đó chỉ là nội dung của tiêu đề Máy chủ từ yêu cầu đến. Máy chủ chính (hoặc Virtualhost bị ràng buộc theo mặc định : 80) sẽ phản hồi tất cả các máy chủ không xác định, do đó, nội dung của thẻ Máy chủ trên trang web đó có thể được đặt thành bất kỳ thứ gì.
Powerlord

4
Lưu ý rằng các máy chủ ảo dựa trên IP sẽ LUÔN trả lời trên IP cụ thể của chúng, vì vậy trong mọi trường hợp , bạn không thể tin tưởng vào giá trị Máy chủ HTTP trên chúng.
Powerlord

1
@Jeff, Nó giống như hỏi "Có thể gọi số điện thoại của pizza hut và yêu cầu nói chuyện với nhân viên KFC?" Chắc chắn tất nhiên bạn có thể yêu cầu bất cứ điều gì bạn muốn. @Powerlord, Điều này không liên quan gì đến các máy chủ ảo dựa trên IP. Máy chủ của bạn, bất kể máy chủ ảo dựa trên IP hay không, trong mọi trường hợp không thể tin tưởng vào Host:giá trị của HTTP trừ khi bạn đã xác minh nó, bằng tay hoặc thông qua thiết lập của SAPI.
Pacerier

3

Tôi không chắc chắn và không thực sự tin tưởng $_SERVER['HTTP_HOST']bởi vì nó phụ thuộc vào tiêu đề từ khách hàng. Theo một cách khác, nếu một tên miền được khách hàng yêu cầu không phải là của tôi, họ sẽ không truy cập vào trang web của tôi vì giao thức DNS và TCP / IP trỏ nó đến đúng đích. Tuy nhiên tôi không biết nếu có thể chiếm quyền điều khiển DNS, mạng hoặc thậm chí máy chủ Apache. Để an toàn, tôi xác định tên máy chủ trong môi trường và so sánh nó với $_SERVER['HTTP_HOST'].

Thêm SetEnv MyHost domain.comtệp .htaccess trên root và thêm mã ths trong Common.php

if (getenv('MyHost')!=$_SERVER['HTTP_HOST']) {
  header($_SERVER['SERVER_PROTOCOL'].' 400 Bad Request');
  exit();
}

Tôi bao gồm tệp Common.php này trong mỗi trang php. Trang này thực hiện mọi yêu cầu cho từng yêu cầu session_start(), sửa đổi cookie phiên và từ chối nếu phương thức đăng đến từ các miền khác nhau.


1
Tất nhiên là có thể bỏ qua DNS. Kẻ tấn công có thể chỉ cần đưa ra một Host:giá trị méo mó trực tiếp vào IP của máy chủ của bạn.
Pacerier

1

XSSsẽ luôn ở đó ngay cả khi bạn sử dụng $_SERVER['HTTP_HOST'], $_SERVER['SERVER_NAME']HOẶC$_SERVER['PHP_SELF']


1

Đầu tiên tôi muốn cảm ơn bạn cho tất cả các câu trả lời và giải thích tốt. Đây là phương pháp tôi đã tạo dựa trên tất cả câu trả lời của bạn để lấy url cơ sở. Tôi chỉ sử dụng nó trong các tình huống rất hiếm. Vì vậy, KHÔNG có sự tập trung lớn vào các vấn đề bảo mật, như các cuộc tấn công XSS. Có lẽ ai đó cần nó.

// Get base url
function getBaseUrl($array=false) {
    $protocol = "";
    $host = "";
    $port = "";
    $dir = "";  

    // Get protocol
    if(array_key_exists("HTTPS", $_SERVER) && $_SERVER["HTTPS"] != "") {
        if($_SERVER["HTTPS"] == "on") { $protocol = "https"; }
        else { $protocol = "http"; }
    } elseif(array_key_exists("REQUEST_SCHEME", $_SERVER) && $_SERVER["REQUEST_SCHEME"] != "") { $protocol = $_SERVER["REQUEST_SCHEME"]; }

    // Get host
    if(array_key_exists("HTTP_X_FORWARDED_HOST", $_SERVER) && $_SERVER["HTTP_X_FORWARDED_HOST"] != "") { $host = trim(end(explode(',', $_SERVER["HTTP_X_FORWARDED_HOST"]))); }
    elseif(array_key_exists("SERVER_NAME", $_SERVER) && $_SERVER["SERVER_NAME"] != "") { $host = $_SERVER["SERVER_NAME"]; }
    elseif(array_key_exists("HTTP_HOST", $_SERVER) && $_SERVER["HTTP_HOST"] != "") { $host = $_SERVER["HTTP_HOST"]; }
    elseif(array_key_exists("SERVER_ADDR", $_SERVER) && $_SERVER["SERVER_ADDR"] != "") { $host = $_SERVER["SERVER_ADDR"]; }
    //elseif(array_key_exists("SSL_TLS_SNI", $_SERVER) && $_SERVER["SSL_TLS_SNI"] != "") { $host = $_SERVER["SSL_TLS_SNI"]; }

    // Get port
    if(array_key_exists("SERVER_PORT", $_SERVER) && $_SERVER["SERVER_PORT"] != "") { $port = $_SERVER["SERVER_PORT"]; }
    elseif(stripos($host, ":") !== false) { $port = substr($host, (stripos($host, ":")+1)); }
    // Remove port from host
    $host = preg_replace("/:\d+$/", "", $host);

    // Get dir
    if(array_key_exists("SCRIPT_NAME", $_SERVER) && $_SERVER["SCRIPT_NAME"] != "") { $dir = $_SERVER["SCRIPT_NAME"]; }
    elseif(array_key_exists("PHP_SELF", $_SERVER) && $_SERVER["PHP_SELF"] != "") { $dir = $_SERVER["PHP_SELF"]; }
    elseif(array_key_exists("REQUEST_URI", $_SERVER) && $_SERVER["REQUEST_URI"] != "") { $dir = $_SERVER["REQUEST_URI"]; }
    // Shorten to main dir
    if(stripos($dir, "/") !== false) { $dir = substr($dir, 0, (strripos($dir, "/")+1)); }

    // Create return value
    if(!$array) {
        if($port == "80" || $port == "443" || $port == "") { $port = ""; }
        else { $port = ":".$port; } 
        return htmlspecialchars($protocol."://".$host.$port.$dir, ENT_QUOTES); 
    } else { return ["protocol" => $protocol, "host" => $host, "port" => $port, "dir" => $dir]; }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.