PHP `use` 导入命名空间导致页面崩溃

PHP `use` import namespace causes page to crash

PHPMailer 在测试脚本中运行良好。但是,它正在崩溃并且不会在另一页上报告任何错误。我已将问题隔离到以下代码行:

use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;

当我省略这些行时,我得到 PHP 错误:

致命错误:未捕获错误:Class 'PHPMailer' 未在 /path/to/file 中找到。php:166 堆栈跟踪:#0 {main} 抛出 /path/to/file.php 第 166 行

当我包含这些行时(我相信我需要这样做才能使用导入的 classes 的名称空间),我只是得到一个空白的白屏。错误报告在页面顶部打开如下:

error_reporting(E_ALL);
ini_set('display_errors', 1);

但是,页面上没有错误报告。

其余 class 文件如下导入,路径正确,因为它们报告没有错误,除非我更改路径。

require '../../../wp-content/plugins/PHPMailer/Exception.php';
require '../../../wp-content/plugins/PHPMailer/PHPMailer.php';
require '../../../wp-content/plugins/PHPMailer/SMTP.php';

我在 PHP 网站上查找有关 use 的信息,但是当我搜索时没有列出任何信息 (http://ca3.php.net/manual-lookup.php?pattern=use&scope=quickref)。

这是 file.php 中的完整代码。我知道还有其他问题,例如数据输入清理等,但我正在重构别人的代码:

<?php

error_reporting(E_ALL);
ini_set('display_errors', 1);
var_dump($_POST);

// PayPal Config Constants
require "../../../mail-config.php";
require "../../../keys-config.php";

/** Send HTTP POST Request for PayPal Payment */
function PPHttpPost($methodName_, $nvpStr_) {

    // Get the environment set in the keys-config.php file
    $environment = PAYPAL_ENVIRONMENT;
    // Use the keys and endpoint for the environment
    if("sandbox" === $environment || "beta-sandbox" === $environment) {
        // Set the API URL
        $API_Endpoint = PAYPAL_API_ENDPOINT_SANDBOX;
        // Set up your API credentials, PayPal end point, and API version.
        $API_UserName = urlencode(PAYPAL_API_USERNAME_SANDBOX);
        $API_Password = urlencode(PAYPAL_API_PASSWORD_SANDBOX);
        $API_Signature = urlencode(PAYPAL_API_SIGNATURE_SANDBOX);
    } else {
        // Set the API URL
        $API_Endpoint = PAYPAL_API_ENDPOINT;
        // Set up your API credentials, PayPal end point, and API version.
        $API_UserName = urlencode(PAYPAL_API_USERNAME);
        $API_Password = urlencode(PAYPAL_API_PASSWORD);
        $API_Signature = urlencode(PAYPAL_API_SIGNATURE);
    }

    // Set the version
    $version = urlencode('51.0');
    // Set the curl parameters.
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $API_Endpoint);
    curl_setopt($ch, CURLOPT_VERBOSE, 1);
    // Turn off the server and peer verification (TrustManager Concept).
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_POST, 1);
    // Set the API operation, version, and API signature in the request.
    $nvpreq = "METHOD=$methodName_&VERSION=$version&PWD=$API_Password&USER=$API_UserName&SIGNATURE=$API_Signature$nvpStr_";
    // Set the request as a POST FIELD for curl.
    curl_setopt($ch, CURLOPT_POSTFIELDS, $nvpreq);
    // Get response from the server.
    $httpResponse = curl_exec($ch);

    // If the method failed
    if(!$httpResponse) {
        exit("$methodName_ failed: ".curl_error($ch).'('.curl_errno($ch).')');
    }

    // Extract the response details.
    $httpResponseAr = explode("&", $httpResponse);
    $httpParsedResponseAr = array();
    foreach ($httpResponseAr as $i => $value) {
        $tmpAr = explode("=", $value);
        if(sizeof($tmpAr) > 1) {
            $httpParsedResponseAr[$tmpAr[0]] = $tmpAr[1];
        }
    }

    // If data in response is invalid
    if((0 == sizeof($httpParsedResponseAr)) || !array_key_exists('ACK', $httpParsedResponseAr)) {
        exit("Invalid HTTP Response for POST request($nvpreq) to $API_Endpoint.");
    }

    // Return the http response
    return $httpParsedResponseAr;
}

// Prepare PayPal Payment Request
// Set request-specific fields.
// 'Authorization' or 'Sale'
$paymentType = urlencode('Sale');
// Name Details
$firstName = urlencode($_POST['firstname']);
$lastName = urlencode($_POST['lastname']);
// Credit Card details
$creditCardType = urlencode($_POST['customer_credit_card_type']);
$creditCardNumber = urlencode($_POST['cardnum']);
$expDateMonth = $_POST['cc_expiration_month'];
// Month must be padded with leading zero
$padDateMonth = urlencode(str_pad($expDateMonth, 2, '0', STR_PAD_LEFT));
$expDateYear = urlencode($_POST['cc_expiration_year']);
$cv = urlencode($_POST['cv']);
// Address Details
$address1 = urlencode($_POST['streetaddy']);
$city = urlencode($_POST['city']);
$state = urlencode($_POST['province']);
$postal_code = urlencode($_POST['postalcode']);
// US or other valid country code
$country = urlencode($_POST['country']);
$price = urlencode($_POST['price']);
// or other currency ('GBP', 'EUR', 'JPY', 'CAD', 'AUD')
$currencyID = urlencode('CAD');

// Add request-specific fields to the request string.
$nvpStr =   "&PAYMENTACTION=$paymentType&AMT=$price&CREDITCARDTYPE=$creditCardType&ACCT=$creditCardNumber".
            "&EXPDATE=$padDateMonth$expDateYear&CVV2=$cv&FIRSTNAME=$firstName&LASTNAME=$lastName".
            "&STREET=$address1&CITY=$city&STATE=$state&ZIP=$postal_code&COUNTRYCODE=$country&CURRENCYCODE=$currencyID";

// Execute the API operation; see the PPHttpPost function above.
$httpParsedResponseAr = PPHttpPost('DoDirectPayment', $nvpStr);

if("SUCCESS" == strtoupper($httpParsedResponseAr["ACK"]) || "SUCCESSWITHWARNING" == strtoupper($httpParsedResponseAr["ACK"])) {

    //Below line is response code from original
    //exit('Direct Payment Completed Successfully: '.print_r($httpParsedResponseAr, true));

    // Require the PHPMailer classes
    use PHPMailer\PHPMailer\PHPMailer;
    use PHPMailer\PHPMailer\Exception;
    require '../../../wp-content/plugins/PHPMailer/Exception.php';
    require '../../../wp-content/plugins/PHPMailer/PHPMailer.php';
    require '../../../wp-content/plugins/PHPMailer/SMTP.php';

  //FIELDS
  $first_name = $_POST['firstname'];
  $last_name = $_POST['lastname'];
  $email_from = $_POST['email'];
  $phone = $_POST['phone'];
  $ad = $_POST['ad'];
  $price = $_POST['price'];
  $edition = $_POST['edition'];
  $issues = $_POST['issues'];
  $category = $_POST['category'];
  $order_id = $_POST['order_id'];
  $email_message = "A Classified Ad has been purchased from the Speaker website. Details of the ad are below.\n\n";

  // Filter the string
  function clean_string($string) {
    $bad = array("content-type","bcc:","to:","cc:","href");
    return str_replace($bad,"",$string);
    $string = filter_var($string, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);
  }

  // Build the Email message body contents
  $email_message .= "<b>Order ID:</b> ".clean_string($order_id)."<br>";
  $email_message .= "<b>First Name:</b> ".clean_string($first_name)."<br>";
  $email_message .= "<b>Last Name:</b> ".clean_string($last_name)."<br>";
  $email_message .= "<b>Email:</b> ".clean_string($email_from)."<br>";
  $email_message .= "<b>Telephone:</b> ".clean_string($phone)."<br>";
  $email_message .= "<b>Category:</b> ".clean_string($category)."<br>";
  $email_message .= "<b>Ad Text:</b> ".clean_string($ad)."<br>";
  $email_message .= "<b>Edition:</b> ".clean_string($edition)."<br>";
  $email_message .= "<b>Number of Issues:</b> ".clean_string($issues)."<br>";
  $email_message .= "<b>Price:</b> ".clean_string($price)."<br>";

  // Set up the email to be sent
  $mail = new PHPMailer(); // create a new object
  $mail->IsSMTP(); // enable SMTP
  $mail->SMTPDebug = 0;
  $mail->SMTPAuth = true; // authentication enabled
  $mail->SMTPSecure = 'ssl'; // secure transfer enabled REQUIRED for Gmail
  $mail->Host = "smtp.gmail.com";
  $mail->Port = 465; // or 587
  $mail->IsHTML(true);
  $mail->Username = SITE_EMAIL_SMTP_USERNAME;
  $mail->Password = SITE_EMAIL_SMTP_PASSWORD;
  $mail->SetFrom(SITE_EMAIL_FROM_ADRESS_LIST);
  $mail->Subject = "Classified Ad Submission From The ".NEWSPAPER_NAME." Website";
  $mail->Body = $email_message;
  // Add all the company email addresses to the send list
  foreach(PAYWALL_NOTIFICATION_EMAIL_ADDRESSES_ARRAY as $email_address){
    $mail->AddAddress($email_address);
  }
    // Add the purchaser's email address to the send list
    $mail->AddAddress($email_from);

  // If mail fails to send
  if(!$mail->Send()) {
    //REDIRECT TO FAILED PAGE
     header( 'Location: /order-not-completed' );
  } else {
   //REDIRECT TO SUCCESS PAGE
   header( 'Location: /success' );
  }

} else  {
    //Below line is response code for testing
    exit('DoDirectPayment failed: ' . print_r($httpParsedResponseAr, true));

    //REDIRECT TO FAILED PAGE
  header( 'Location: /order-not-completed' );
}

?>

这意味着您的PHP版本太旧了。 Namespacesuse 语法是在 PHP 5.3 中引入的,这已经过时很多年了。

PHPMailer 6.0.x 至少需要 PHP 5.5,因此请更新您的 PHP,最好是最新版本(目前为 7.3)。

这是描述使用 PHP 的 use 函数导入名称空间的页面:http://php.net/manual/en/language.namespaces.importing.php

Scoping rules for importing

The use keyword must be declared in the outermost scope of a file (the global scope) or inside namespace declarations. This is because the importing is done at compile time and not runtime, so it cannot be block scoped. The following example will show an illegal use of the use keyword: namespace Languages;

function toGreenlandic() {

use Languages\Danish;

// ... }

虽然上面的代码没有在函数中使用 use 语句,但它不在文件的顶部,并且在 use 语句之前声明了其他函数。在将 use 语句移动到文件顶部后,我测试了上面的代码

简而言之:始终将 use 语句放在 PHP 文件的顶部和函数或 类.

之外