【问题标题】:PHP decode, alter and encode JSONPHP 解码、更改和编码 JSON
【发布时间】:2015-02-07 19:21:45
【问题描述】:

我猜这个问题已经在某个地方得到了回答,但我找不到解决方案,我把头发扯掉了。我有一个存储在 MySQL 中的 JSON 数组,如下所示:

[{"ip":"8.8.8.8","name":"Bob"},{"ip":"","name":""},{"ip":"","name":""},{"ip":"","name":""}]

我想替换特定对象的“ip”和“name”。所以我将$slot_num 设置为0 并尝试更改值和UPDATE 数据库。下面的 SELECT 子句应该没问题,因为它在其他地方多次使用。

//Recieves POST info such as ip=1.1.1.1&group=204&slot=3&name=help
$ip = $_POST['ip'];
$group_id = $_POST['group'];
$slot_num = $_POST['slot'] -1; //PHP receives slot num increased by 1. IE- $slot_num 1 would be array[0]
$name = $_POST['name'];

if($result = $mysqli->query("SELECT * FROM `open_groups` WHERE `group_id` = $group_id")) {
    $row = mysqli_fetch_array($result);
    $slot_ar = json_decode($row['players'], true);
    //Check if array has correct number slots
    if($slot_num => count($slot_ar) || !is_int($slot_num)){
        die('Injection attempt');
    }

    $slot_ar[$slot_num]['ip'] = $ip;
    $slot_ar[$slot_num]['name'] = $name;
    $players = json_encode($slot_ar);
    $players = $mysqli->real_escape_string($players);
    if(!$mysqli->query("UPDATE `open_group` SET players = '$players' WHERE group_id = $group_id")) {
        echo $mysqli->error;
        exit;
    }
    if(!$mysqli->query("INSERT INTO `occupied`(`ip`, `group`) VALUES ('$ip', '$group_id')")) {
        echo $mysqli->error;
        exit;
    }
    echo "Success";
}
else echo $mysqli->error;

我是在错误地访问数组还是什么?

固定代码

$ip = $_POST['ip'];
$group_id = $_POST['group'];
$slot_num = $_POST['slot']; //PHP receives slot num increased by 1. IE- $slot_num 1 would be array[0]
$name = $_POST['name'];

if($result = $mysqli->query("SELECT * FROM `open_groups` WHERE `group_id` = $group_id")) {
$row = mysqli_fetch_array($result);
$slot_ar = json_decode($row['players'], true);
//Check if array has correct number slots
if($slot_num-1 >= count($slot_ar) || !is_numeric($slot_num)){
    echo "Injection attempt";
    exit;
}
$slot_ar[$slot_num-1]['ip'] = "$ip";
$slot_ar[$slot_num-1]['name'] = "$name";
$players = json_encode($slot_ar);
$players = $mysqli->real_escape_string($players);
if(!$mysqli->query("UPDATE `open_groups` SET players = '$players' WHERE `group_id` = $group_id")) {
    echo "Update error";
    exit;
}
if(!$mysqli->query("INSERT INTO `occupied`(`ip`, `group`) VALUES ('$ip', '$group_id')")) {
    echo "Occupied error";
    exit;
}
echo "Success";
}
else echo "Fail";

【问题讨论】:

  • 你没有提到到底是什么问题。
  • 您没有在任何地方转义$players,因此您有语法错误并且可能存在SQL 注入漏洞。
  • @AlexanderO'Mara 转义 $name 和 $ip 而不是 $player 不是更好吗?此外,如果您想考虑注入,您需要检查 $_POST['num'] 不高于 json 数组中的位置数量,否则人们将通过注入创建新条目。
  • 我逃脱了$name,我将其添加到问题中。问题是数据库中的数据没有改变。
  • @CharlesForest 不!需要转义整个 JSON 字符串,而不仅仅是一些索引。确实,$slot_num 可能高于应有的值,这可能应该被提防,但这并不是一个危险的问题。

标签: php mysql arrays json


【解决方案1】:

你需要转义 $players,因为 json 数组中充满了引号,所以当你使用查询将其插入数据库时​​,mysql 将无法执行和理解它。
也尝试在转义后将变量放在单引号内。试试这个:

$players = $mysqli->real_escape_string($players);
$mysqli->query("UPDATE `open_group` SET players = '$players' WHERE group_id = '$group_id' ");

【讨论】:

  • @AlexanderO'Mara 我在代码的第一行中转义了 $players,它如何对 SQL 注入有效?你确定吗?你能举个例子吗?
  • 没关系,我猜我只是瞎了一会儿。那就投赞成票吧!
  • 我真的很喜欢来自@AlexanderO'Mara 的警告。 stackoverflow.com/questions/5741187/…
  • @CharlesForest 他正在使用 MySQLi 的real_escape_string,这已经足够了。不过,变量绑定通常更好。
  • “足够体面”!= 好。我改变了问题参考,我对那个不好。
【解决方案2】:

正如 AlexanderO'Mara 指出的那样,您真的应该选择 bind_param() 而不是 mysqli_escape_string(),这在某些情况下已被证明是不可靠的。我使用 PDO 语句,所以这是未经测试的。

来源:mysqli real escape string, should I use it?

$slot_num = $_POST['num'];
$name = $_POST['name'];

// Initial select
$sql = "SELECT * FROM `open_groups` WHERE `group_id` = ?";
$stmt = $mysqli->prepare($sql);
$stmt->bind_param('d', $group_id);
$stmt->execute();

if ($stmt->errno) {
  die("Error : " . $stmt->error);
}

$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
    $slot_ar = json_decode($row['players'], true); //Get JSON array

    // Make sure $slot_num isn't bigger than desired
    if($slot_num > count($slot_ar) || !is_int($slot_num)){
        die('Injection attempt');
    }
    // Store new variables in the array
    $slot_ar[$slot_num]['ip'] = "$ip";
    $slot_ar[$slot_num]['name'] = "$name";

    // encode the new $players
    $players = json_encode($slot_ar);

    // new SQL query
    $sql = "UPDATE `open_group` SET players = ? WHERE group_id = ?";
    $stmt = $mysqli->prepare($sql);
    $stmt->bind_param('sd', $players, $group_id);
    $stmt->execute();
    if ($stmt->errno) {
      die("Error : " . $stmt->error);
    }

}

【讨论】:

  • 您真的阅读过您的 SO 链接吗?在答案的最后它说:“或者 PDO 和 mysql_escape_string 在处理一些极其罕见的编码方面没有区别。”
  • 略读,我对那个不好。我更改了链接。
  • 然后在您的新链接中,它说:“您在查询中的变量周围使用单引号 (' ') 的事实是保护您免受这种情况的影响”这就是我使用的原因,相信我我的代码是安全的,我对它进行了很多研究
  • 导致未准备好的语句不安全的错误是我希望那些不保护自己免受 SQL 注入攻击的人会犯的错误。你是对的,你的代码是安全的。我 +1 了。
  • 嗯,你也是对的。有时最好不要挖代码,使用准备好的函数!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-07
  • 2017-05-31
  • 2014-10-10
相关资源
最近更新 更多