php - 如何检查表或表行是否为空?

时间:2014-10-17 19:11:34

标签: php mysql mysqli

我定义了以下函数来检查表行是否为空

function check_table($table) {
    global $con;
    $result = mysqli_query($con, "SELECT * FROM $table");
    return (mysqli_num_rows($result) > 0) ? true : false;
}

然后调用它来填充表

// check if payment table is empty, then insert into in, else update it
if(check_table('payment_details') == false) {
    insert_into_table('payment_details',$payment_detail);
} else {
    update_table($session_user_id,'payment_details',$payment_detail);
}

insert_into_table()已定义

function insert_into_table($table,$register_data) {
    global $con;
    array_walk($register_data, 'array_sanitize');

    $fields = '`' . implode('`, `', array_keys($register_data)) . '`';
    $data = '\'' . implode('\', \'', $register_data) . '\'';
    mysqli_query($con , "INSERT INTO $table ($fields) VALUES ($data)");
}

但它没有按照需要返回,并且在执行它之后表仍然是空的。它不起作用。

所以我错了?

任何帮助都会受到赞赏。

感谢

NEW UPDATED

这是我的所有代码看起来,只是确保我是正确的?如果没有,请给我一些改进建议。

的init.php

$session_user_id = $_SESSION['userid'];
//users table
$user_data = user_data($session_user_id,'users', 'id','username','password','first_name','last_name','email','allow_email',
'password_recover','active','city','state','country','phone','custom','date','plan','duration','domain','amount',
'pp_txn_id', 'pp_item_no','pp_payment_status','pp_payer_email','pp_payment_date','pz_reference_no', 'pz_item_no',
'pz_payment_status','pz_payer_email','pz_payment_date','expiry','status','cpanel');

// for paypal payments
$pp_data = user_data($session_user_id,'pp_details','pp_txn_id','pp_item_no','pp_payment_status','pp_payer_email','pp_payment_date');
// for payza payments
$pz_data = user_data($session_user_id,'pz_details','pz_reference_no','pz_item_no','pz_payment_status','pz_payer_email','pz_payment_date');

member.php

require_once(get_template_directory().'/member/core/init.php');

$customField = $user_data['custom'];
//check if transaction is done
if ( $customField == $user_data['id'] && ($user_data['pz_payment_status'] == 'Success') || ($user_data['pp_payment_status'] == 'Completed') ) {
    //info for pp_details table
        $pp_detail = array(
            'id'                => $user_data['id'],
            'pp_txn_id'         => $user_data['pp_txn_id'],
            'pp_item_no'        => $user_data['pp_item_no'],
            'pp_payment_status' => $user_data['pp_payment_status'],
            'pp_payer_email'    => $user_data['pp_payer_email'],
            'pp_payment_date'   => $user_data['pp_payment_date'],
        );
        //info for pz_details table
        $pz_detail = array(
            'id'                => $user_data['id'],
            'pz_reference_no'   => $user_data['pz_reference_no'],
            'pz_item_no'        => $user_data['pz_item_no'],
            'pz_payment_status' => $user_data['pz_payment_status'],
            'pz_payer_email'    => $user_data['pz_payer_email'],
            'pz_payment_date'   => $user_data['pz_payment_date'],
        );
        //reset the users table if transaction is success
        $update_data = array(
            'status' => 'Active',
            'pp_txn_id' => NULL,
            'pp_item_no' => NULL,
            'pp_payment_status' => NULL,
            'pp_payer_email' => NULL,
            'pp_payment_date' => NULL,
            'pz_reference_no' => NULL,
            'pz_item_no' => NULL,
            'pz_payment_status' => NULL,
            'pz_payer_email' => NULL,
            'pz_payment_date' => NULL,
        );
    // check if payment table is empty, then insert into in
    if(check_table($session_user_id,'pp_details') == false) {
        if ($user_data['pp_payment_status'] == 'Completed') {
            insert_into_table('pp_details',$pp_detail);
            update_user($session_user_id, $update_data);
        }
    } elseif (check_table($session_user_id,'pz_details') == false) {
        if ($user_data['pz_payment_status'] == 'Success') {
            insert_into_table('pz_details',$pz_detail);
            update_user($session_user_id, $update_data);
        }
    }
    // make sure if user_data transaction id's not match with payment_data details, then activate the package
    if ( ($user_data['pp_txn_id']) != ($pp_data['pp_txn_id']) ) {
        // update the pp_details table
        update_table($session_user_id,'pp_details',$pp_detail);
        // reset the users table and activate package
        update_user($session_user_id, $update_data);

    } elseif ( ($user_data['pz_reference_no']) != ($pz_data['pz_reference_no']) ) {
        // update the pz_details table
        update_table($session_user_id,'pz_details',$pz_detail);
        // reset the users table and activate package
        update_user($session_user_id, $update_data);
    }
    // email credentials 
    if ( $user_data['pp_payment_status'] == 'Completed' ) {
        $transactionID  = $pp_data['pp_txn_id'];
        $itemNo         = $pp_data['pp_item_no'];
        $paymentStatus  = $pp_data['pp_payment_status'];
        $paymentDate    = $pp_data['pp_payment_date'];
        if ($pp_data['pp_payer_email'] !== $user_data['email']) {
            $customer_Email = array($pp_data['pp_payer_email'],$user_data['email']);
        } else {
            $customer_Email = array($user_data['email']);
        }
    } elseif ( $user_data['pz_payment_status'] == 'Success' ) {
        $transactionID  = $pz_data['pz_reference_no'];
        $itemNo         = $pz_data['pz_item_no'];
        $paymentStatus  = $pz_data['pz_payment_status'];
        $paymentDate    = $pz_data['pz_payment_date'];
        if ($pz_data['pz_payer_email'] !== $user_data['email']) {
            $customer_Email = array($pz_data['pz_payer_email'],$user_data['email']);
        } else {
            $customer_Email = array($user_data['email']);
        }
    }

    $message = "Thank You <b>".$user_data['first_name']."</b> for using our service.<br> Your Transaction details are below:<br><br>
            Transaction ID/Reference: $transactionID<br>
            Item No: $itemNo <br>
            Payment Status: $paymentStatus <br>
            Payment Date: $paymentDate <br><br>
            Kind Regards <br>
            - HostPLUS1 &copy; ".date('Y')."
    ";
    if ( isset($_GET['success']) && empty($_GET['success']) ) {
        //if sucess then refresh the page to remove the $_GET val
        refresh('3',$_SERVER['SCRIPT_URI']);
        if ($user_data['status'] == 'Active') {
            email($customer_Email,'Thank you, your payment has been completed',$message);

        }
    }
};

我已将所有功能定义在名为user_functions.php

的单独文件中

3 个答案:

答案 0 :(得分:2)

Hsn,你在哪里指定检查表的条件?您正在说"SELECT * FROM $table",但您没有指定条件(或Yegor指出的限制)。这意味着如果您的payment_details表中只有 ONE (1)交易,则不会处理任何新交易。您应该根据条件过滤结果。

我相信您正在为PayPal IPN写这个,所以我会按照这样格式化我的答案。在所有重写之下,您将看到有关我为什么建议我做的信息。

这就是我建议重写它的方式:

/* Escape the variables right away */
// global $con; // uncomment this if you need to. I don't know where in your code it's defined
$clean_ppTxnId = ""; // we'll use this in check table.
foreach($payment_detail as $key => $value){
   $escapedKey = $con->escape_string($key);
   $escapedValue = $con->escape_string($value);
   if($key == 'pp_txn_id'){  $clean_ppTxnId = $escapedValue;  }
   unset($payment_detail[$key]);
   $payment_detail[$escapedKey] = $escapedValue;
}
// the payment details have now been looped, sanitized and replaced.

// check if payment table is empty, then insert into in, else update it
if(check_table('payment_details') == false) {
    /* new payment that we've never seen before */
    insert_into_table('payment_details',$payment_detail);
} else {
    /* if we go into the else statement, this exact payment has already
     * been processed once. */

    /* update_table($session_user_id,'payment_details',$payment_detail); */

    /*******
     * The line above is going to force you to either double process or
     * you'll overwrite PayPal transaction records.
     * Instead, this should be regarded as PayPal sending the transaction
     * to your IPN a second time (which does happen).
     ******/
}
/* If you're done with all database transactions at this point, you should call $con->close(); */

现在为check_table功能

function check_table($table, $clean_ppTxnId) {
    global $con;
    $result = $con->("SELECT * FROM `$table` WHERE (`pp_txn_id` = '$clean_ppTxnId') LIMIT 1");
    // I've added a where conditional to filter results and a LIMIT statement as Yegor suggested.
    $returnVal = ($result->num_rows > 0) ? true : false;
    $result->close();
    return returnVal;
}

最后是insert_into函数:

function insert_into_table($table,$register_data) {
    global $con;
    /* removed array_walk because my solution filters the data in before
     * calls this function.
     */

    $fields = '`' . implode('`, `', array_keys($register_data)) . '`';
    $data = '\'' . implode('\', \'', $register_data) . '\'';
    $result = $con->query("INSERT INTO `$table` ($fields) VALUES ($data);");
    // you can check the result for something if you want, but you shouldn't need to.
    $result->close();
}

编辑摘要:

  • 我添加了条件检查,因此您的IPN可以处理超过1笔付款。
  • 我添加了对双重处理付款的保护。
  • 我实现了MySQLi的real_escape_string(也称为escape_string)功能。此函数使用MySQL数据库的设置来清理/转义输入。也许你的array_sanitize()函数已经这样做了,但我决定添加它,因为你没有发布这个函数。
  • 我已将所有MySQLi命令/查询切换为OOP样式。这部分是出于偏好,但我也发现它们更容易理解并且写得更快。
  • 最后,我添加了关闭查询结果的命令。这释放了数据库资源和服务器内存。当脚本完成运行/退出时,这些将自动关闭,但如果您提前关闭它们,服务器和放大器将会关闭它们。数据库都可以更快地获得资源。

由于并非所有代码都已过帐,因此您必须决定是否应将任何这些修改添加到您的代码中;但是,如果这是我认为的PayPal IPN,那么这些编辑可能会有用。无论如何,你必须做出这个决定。


<强>更新 好的,在您更新后,我对您的代码及其逻辑有一些疑问。

这是您的代码:

// make sure if user_data transaction id's not match with payment_data details, then activate the package
if (!empty($payment_data['pp_txn_id']) === !empty($user_data['pp_txn_id']) || !empty($payment_data['pz_reference_no']) === !empty($user_data['pz_reference_no'])) {
    $update_data = array(
        'status' => 'Active',
    );
    update_user($session_user_id, $update_data);
}

评论说make sure if user_data transaction id's not match with payment_data details, then activate the package,但这个if语句没有这样做。事实上,这个if语句可能会做一些你不希望它做的事情。

第一部分说if(!empty($array['index']) === !empty($another_array['index']))让我们打破它。

  • empty()返回一个布尔值,指示变量是否没有内容(如果字符串为empty'',则对字符串调用""将为true 。因此,让$array['index'] = "foo";,然后empty($array['index'])变为empty("foo")。我们知道这将返回false,因为该字符串不为空。
  • 接下来你说!empty(...)。所以以扩展的形式$boolean_returned_by_not_empty = (empty(...) ? false : true);。您将布尔值切换到相反的位置。这很好,也很容易理解。
  • 然后你说!empty(...) === !empty($another_array['index'])

这里第一部分的逻辑失败了。您在评论中表示要比较它们是否匹配,但您要比较的是它们是否为空或两者都包含内容。这意味着如果您分配$payment_details['pp_txn_id'] = "foo";$user_data['pp_txn_id'] = "bar";,if语句将会运行,因为尽管它们不匹配,但它们都不为空。同样,如果它们匹配($payment_details['pp_txn_id'] = "foobar";$user_data['pp_txn_id'] = "foobar";),您的代码将运行if语句来更新表。

在if语句的第二部分,你做了同样的事情,然后只是说if either pair contains two strings with some data (this data doesn't even have to match), then go ahead and update the table.

在我看来,当你想知道它们是否匹配时,这没有逻辑意义。我认为更好的检查是:

if( ($payment_details['pp_txn_id'] !== $user_data['pp_txn_id']) ||
    ($payment_data['pz_reference_no'] !== !$user_data['pz_reference_no']) ){

    $update_data = array(
        'status' => 'Active',
    );
    update_user($session_user_id, $update_data);

}

此外,在看到您添加的代码后,我现在建议您执行array_walk($payment_detail, 'array_sanitize');我放置foreach循环的位置。然后,只需在$clean_ppTxnId之后指定array_walk即可。我现在可以看到您的array_sanitize是安全的。


众所周知,这个剧本仍然存在问题,因为它缺乏细节和内容。基本思路应该是:

  1. 用户付款
  2. PayPal与您的IPN联系
  3. 您签入数据库以查看您是否已经处理了此交易ID。如果你有,请忽略它。
  4. 如果您尚未处理,请检查项目的费用(settle_amount;恶意购买者可能会更改HTML amount属性),检查每个其他必要变量是否满足预期标准。如果没有,则结帐被篡改,不应处理。
  5. 如果收银台没有被篡改,一切似乎都很好,你应该继续。继续清理变量。
  6. 现在将事务详细信息记录到数据库的事务表中。
  7. 如果用户在购买前注册,您应该尝试从用户表中获取与用户相关的行,然后继续执行步骤#8。如果他们在购买时已注册,请执行INSERT INTO <Table name for the user table goes here> (<column name 1>, <column name 2>, ...) VALUES (<value 1>, <value 2>, ...);添加一行。如果您刚注册用户,请执行步骤#9。
  8. 如果您使用的是#8,那么您需要更新用户而不是创建新用户。在此步骤中,您应检查是否已成功从数据库中获取用户的查询。如果确实成功并且系统上存在用户,则继续更新用户的行并将status设置为Active。否则,请在数据库的警告表中记录错误,以便稍后查看,以确定是否需要退款或更正您的代码。
  9. 可选)如果您愿意,可以发送电子邮件(我不会详细说明,但您可以使用PHP的mail()功能)到payer_email通知用户该交易已被处理。

答案 1 :(得分:0)

我找到了我的错误并修好了

我的数组'pz_payment_data' => $user_data['pz_payment_data'],

中存在拼写错误
$payment_detail = array(
    'id' => $user_data['id'],
    'pp_txn_id' => $user_data['pp_txn_id'],
    'pp_payment_date' => $user_data['pp_payment_date'],
    'pz_reference_no' => $user_data['pz_reference_no'],
    'pz_payment_date' => $user_data['pz_payment_date'],
);

我修复它现在可以正常工作:)

答案 2 :(得分:0)

你的功能不好:

function check_table($table) {
    global $con;
    $result = mysqli_query($con, "SELECT * FROM $table");
    return (mysqli_num_rows($result) > 0) ? true : false;
}

因为它只选择所有行来获取bool结果,我认为你可以改进它:

function check_table($table) {
    global $con;
    $result = mysqli_query($con, "SELECT * FROM $table LIMIT 1");
    return (mysqli_num_rows($result) > 0) ? true : false;
}