PHP 警告:sprintf():中的参数太少
PHP Warning: sprintf(): Too few arguments in
我有一个运行脚本的 cronjob -> 从不同的 iTunes 商店获取数据。有时我会收到上述错误消息。
我认为这是因为特殊字母或类似的东西。有没有办法检查问题到底出在哪里?其中 "special character" 是错误的原因。是否有 IF 语句的解决方法?
我无法重现错误,因为它并不总是出现。在这方面得到帮助会很棒。
代码如下:
foreach ($Kategorien->entry as $item) {
$id = addslashes($item->id);
$title = utf8_decode(addslashes($item->title));
$preview = addslashes($item->link[1]["href"]);
$namespaces = $item->getNameSpaces(true);
$im = $item->children($namespaces['im']);
$track_title = utf8_decode(addslashes($im->name));
$track_artist = utf8_decode(addslashes($im->artist));
$track_amount = addslashes($im->price->attributes()->amount);
$track_currency = utf8_decode(addslashes($im->price->attributes()->currency));
$release_date = addslashes($im->releaseDate);
$image = addslashes($im->image[2]);
$entry_id['im'] = $item->id->attributes('im', TRUE);
$track_id = addslashes($entry_id['im']['id']);
$category_id['im'] = $item->category->attributes('im', TRUE);
$genre_id = addslashes($category_id['im']['id']);
$genre_cat = utf8_decode(addslashes($item->category->attributes()->term));
$insertSQL = sprintf("UPDATE track_itunes_countries_total SET modified = NOW(), modified_genre = '$genre_name' WHERE id = ".$row_select_country['id']."");
$Result1 = mysql_query($insertSQL, $con) or die(mysql_error());
$insertSQL = sprintf("INSERT INTO track_itunes_".$cc."_total (id, title, preview, track_title, track_artist, track_amount, track_currency, release_date, image, track_id, genre_id, genre_cat, country, Online, Approved) VALUES ('$id', '$title', '$preview', '$track_title', '$track_artist', '$track_amount', '$track_currency', '$release_date', '$image', '$track_id', '$genre_id', '$genre_cat', '$cc', '1', '1') ON DUPLICATE KEY UPDATE title='$title',preview='$preview',track_title='$track_title',track_artist='$track_artist',track_amount='$track_amount',track_currency='$track_currency',release_date='$release_date',image='$image',track_id='$track_id',genre_id='$genre_id',genre_cat='$genre_cat',country='$cc'");
$Result1 = mysql_query($insertSQL, $con);}
首先:您应该使用 mysql_real_escape_string() 或更好地使用 mysqli 而不是 mysql 函数,因为 mysql 已被弃用。
对于错误消息,您应该查看 sprintf 的文档以了解错误。
或者只使用适当的连接。
$string = "fooo='".$var."'";
而不是你懒惰的符号
$string = "fooo='$var'";
这是一个例子,包括 mysql_real_escape_string():
$query = sprintf("SELECT * FROM users WHERE user='%s' AND password='%s'",
mysql_real_escape_string($user),
mysql_real_escape_string($password));
您还可以为绑定变量指定具体位置:
$query = sprintf("SELECT * FROM users WHERE user='%2$s' AND password='%1$s'",
mysql_real_escape_string($password),
mysql_real_escape_string($user)
);
对于 mysql_query(),如果您不使用超过 1 个数据库连接,则无需提供连接 link $con。
mysql_query($query);
会成功的。
这不是 sprintf 的工作方式。
sprintf 表示字符串 printf——您正在执行一个 printf,其中 returns 一个字符串而不是直接打印到标准输出。
printf 的工作方式是将占位符分配给格式字符串(第一个参数),并将占位符的绑定值作为后续参数。
例如
$s = sprintf("SELECT * FROM %s WHERE id = %d", 'some_table', $id);
这在某种程度上是一种净化输入的幼稚方法,因为您使用以下格式强制将变量转换为某些类型:在本例中为 %s 和 %d for string 和 decimal/digit。在运行时,这些将被替换为 "some_table",无论 intval($id) 是什么。
你得到 "Too few arguments" 的原因是你缺少绑定值。
我会以切线的方式回答,因为您使用的是已弃用的 mysql_* 库,而是向您展示 PDO。这将要么 a) 解决您的问题,要么 b) 提供更多信息的错误消息以帮助您进行调试。
foreach ($Kategorien->entry as $item) {
$id = $item->id;
$title = utf8_decode($item->title);
$preview = $item->link[1]["href"];
$namespaces = $item->getNameSpaces(true);
$im = $item->children($namespaces['im']);
$track_title = utf8_decode($im->name);
$track_artist = utf8_decode($im->artist);
$track_amount = $im->price->attributes()->amount;
$track_currency = utf8_decode($im->price->attributes()->currency);
$release_date = $im->releaseDate;
$image = $im->image[2];
$entry_id['im'] = $item->id->attributes('im', TRUE);
$track_id = $entry_id['im']['id'];
$category_id['im'] = $item->category->attributes('im', TRUE);
$genre_id = $category_id['im']['id'];
$genre_cat = utf8_decode($item->category->attributes()->term);
$insertSQL = "UPDATE track_itunes_countries_total
SET modified = NOW(), modified_genre = :genre_name
WHERE id = :row_id");
$stmt = $pdo->prepare($insertSQL);
$stmt->bindValue(':genre_name', $genre_name);
$stmt->bindValue(':row_id', $row_select_country['id']);
$success = $stmt->execute();
if(!$success){
//something bad happened
}
//use whitelist techniques to guarantee valid, non-malicious input
//with table names or column names. whitelistTableName is a function
//that YOU have to write.
$clean_table_name = whitelistTableName("track_itunes_{$cc}_total");
$insertSQL = "INSERT INTO {$clean_table_name}
(id, title, preview, track_title,
track_artist, track_amount, track_currency,
release_date, image, track_id, genre_id,
genre_cat, country, Online, Approved)
VALUES
(:id, :title, :preview, :track_title,
:track_artist, :track_amount, :track_currency,
:release_date, :image, :track_id, :genre_id,
:genre_cat, :country, :Online, :Approved)
ON DUPLICATE KEY UPDATE
title=:title_u,preview=:preview_u,track_title=:track_title_u,
track_artist=:track_artist_u,track_amount=:track_amount_u,
track_currency=:track_currency_u,release_date=:release_date_u,
image=:image_u,track_id=:track_id_u,genre_id=:genre_id_u,
genre_cat=:genre_cat_u,country=:cc_u");
$stmt = $pdo->prepare($insertSQL);
$stmt->bindValue(':id', $id);
$stmt->bindValue(':title', $title);
$stmt->bindValue(':preview', $preview);
$stmt->bindValue(':track_title', $track_title);
$stmt->bindValue(':track_artist', $track_artist);
$stmt->bindValue(':track_amount', $track_amount);
$stmt->bindValue(':track_currency', $track_currency);
$stmt->bindValue(':release_date', $release_date);
$stmt->bindValue(':image', $image);
$stmt->bindValue(':track_id', $track_id);
$stmt->bindValue(':genre_id', $genre_id);
$stmt->bindValue(':genre_cat', $genre_cat);
$stmt->bindValue(':country', $cc);
$stmt->bindValue(':Online', 1);
$stmt->bindValue(':Approved', 1);
//some drivers doesn't allow to have a named placeholder to appear more than once so we must duplicate those.
$stmt->bindValue(':id_u', $id);
$stmt->bindValue(':title_u', $title);
$stmt->bindValue(':preview_u', $preview);
$stmt->bindValue(':track_title_u', $track_title);
$stmt->bindValue(':track_artist_u', $track_artist);
$stmt->bindValue(':track_amount_u', $track_amount);
$stmt->bindValue(':track_currency_u', $track_currency);
$stmt->bindValue(':release_date_u', $release_date);
$stmt->bindValue(':image_u', $image);
$stmt->bindValue(':track_id_u', $track_id);
$stmt->bindValue(':genre_id_u', $genre_id);
$stmt->bindValue(':genre_cat_u', $genre_cat);
$stmt->bindValue(':country_u', $cc);
$stmt->bindValue(':Online_u', 1);
$stmt->bindValue(':Approved_u', 1);
$success = $stmt->execute();
if(!$success){
//something bad happened
}
}
这里有更多内容可供阅读:http://php.net/manual/en/book.pdo.php它非常简单,而且比 mysql_* 库要好得多
扩展白名单技术:有几种方法可以净化用户输入。一种是转义:这是在用户输入像文本输入一样 "open ended" 的情况下完成的,其中存在无限多种可能性。如上所示,准备好的语句对此非常完美。
另一种可能性是白名单,当用户输入的有效可能性有限(例如,单选按钮、复选框、选项选择等)并且任何无效输入都是错误或恶意时,它很有用。
示例如下:
whitelistTableName($tablename){
$allowedTables = array('tbl1', 'tbl2', 'tbl3');
if(in_array($tablename, $allowedTables)){
return $tablename;
} else {
throw new Exception('Malicious attempt detected');
}
}
这是非常基础的,但可以让您入门。更好的方法是查询您的 information_schema 数据库以获取每个有效的 table 名称,而不是手动对它们进行硬编码。
我有一个运行脚本的 cronjob -> 从不同的 iTunes 商店获取数据。有时我会收到上述错误消息。
我认为这是因为特殊字母或类似的东西。有没有办法检查问题到底出在哪里?其中 "special character" 是错误的原因。是否有 IF 语句的解决方法?
我无法重现错误,因为它并不总是出现。在这方面得到帮助会很棒。
代码如下:
foreach ($Kategorien->entry as $item) {
$id = addslashes($item->id);
$title = utf8_decode(addslashes($item->title));
$preview = addslashes($item->link[1]["href"]);
$namespaces = $item->getNameSpaces(true);
$im = $item->children($namespaces['im']);
$track_title = utf8_decode(addslashes($im->name));
$track_artist = utf8_decode(addslashes($im->artist));
$track_amount = addslashes($im->price->attributes()->amount);
$track_currency = utf8_decode(addslashes($im->price->attributes()->currency));
$release_date = addslashes($im->releaseDate);
$image = addslashes($im->image[2]);
$entry_id['im'] = $item->id->attributes('im', TRUE);
$track_id = addslashes($entry_id['im']['id']);
$category_id['im'] = $item->category->attributes('im', TRUE);
$genre_id = addslashes($category_id['im']['id']);
$genre_cat = utf8_decode(addslashes($item->category->attributes()->term));
$insertSQL = sprintf("UPDATE track_itunes_countries_total SET modified = NOW(), modified_genre = '$genre_name' WHERE id = ".$row_select_country['id']."");
$Result1 = mysql_query($insertSQL, $con) or die(mysql_error());
$insertSQL = sprintf("INSERT INTO track_itunes_".$cc."_total (id, title, preview, track_title, track_artist, track_amount, track_currency, release_date, image, track_id, genre_id, genre_cat, country, Online, Approved) VALUES ('$id', '$title', '$preview', '$track_title', '$track_artist', '$track_amount', '$track_currency', '$release_date', '$image', '$track_id', '$genre_id', '$genre_cat', '$cc', '1', '1') ON DUPLICATE KEY UPDATE title='$title',preview='$preview',track_title='$track_title',track_artist='$track_artist',track_amount='$track_amount',track_currency='$track_currency',release_date='$release_date',image='$image',track_id='$track_id',genre_id='$genre_id',genre_cat='$genre_cat',country='$cc'");
$Result1 = mysql_query($insertSQL, $con);}
首先:您应该使用 mysql_real_escape_string() 或更好地使用 mysqli 而不是 mysql 函数,因为 mysql 已被弃用。
对于错误消息,您应该查看 sprintf 的文档以了解错误。
或者只使用适当的连接。
$string = "fooo='".$var."'";
而不是你懒惰的符号
$string = "fooo='$var'";
这是一个例子,包括 mysql_real_escape_string():
$query = sprintf("SELECT * FROM users WHERE user='%s' AND password='%s'",
mysql_real_escape_string($user),
mysql_real_escape_string($password));
您还可以为绑定变量指定具体位置:
$query = sprintf("SELECT * FROM users WHERE user='%2$s' AND password='%1$s'",
mysql_real_escape_string($password),
mysql_real_escape_string($user)
);
对于 mysql_query(),如果您不使用超过 1 个数据库连接,则无需提供连接 link $con。
mysql_query($query);
会成功的。
这不是 sprintf 的工作方式。
sprintf 表示字符串 printf——您正在执行一个 printf,其中 returns 一个字符串而不是直接打印到标准输出。
printf 的工作方式是将占位符分配给格式字符串(第一个参数),并将占位符的绑定值作为后续参数。
例如
$s = sprintf("SELECT * FROM %s WHERE id = %d", 'some_table', $id);
这在某种程度上是一种净化输入的幼稚方法,因为您使用以下格式强制将变量转换为某些类型:在本例中为 %s 和 %d for string 和 decimal/digit。在运行时,这些将被替换为 "some_table",无论 intval($id) 是什么。
你得到 "Too few arguments" 的原因是你缺少绑定值。
我会以切线的方式回答,因为您使用的是已弃用的 mysql_* 库,而是向您展示 PDO。这将要么 a) 解决您的问题,要么 b) 提供更多信息的错误消息以帮助您进行调试。
foreach ($Kategorien->entry as $item) {
$id = $item->id;
$title = utf8_decode($item->title);
$preview = $item->link[1]["href"];
$namespaces = $item->getNameSpaces(true);
$im = $item->children($namespaces['im']);
$track_title = utf8_decode($im->name);
$track_artist = utf8_decode($im->artist);
$track_amount = $im->price->attributes()->amount;
$track_currency = utf8_decode($im->price->attributes()->currency);
$release_date = $im->releaseDate;
$image = $im->image[2];
$entry_id['im'] = $item->id->attributes('im', TRUE);
$track_id = $entry_id['im']['id'];
$category_id['im'] = $item->category->attributes('im', TRUE);
$genre_id = $category_id['im']['id'];
$genre_cat = utf8_decode($item->category->attributes()->term);
$insertSQL = "UPDATE track_itunes_countries_total
SET modified = NOW(), modified_genre = :genre_name
WHERE id = :row_id");
$stmt = $pdo->prepare($insertSQL);
$stmt->bindValue(':genre_name', $genre_name);
$stmt->bindValue(':row_id', $row_select_country['id']);
$success = $stmt->execute();
if(!$success){
//something bad happened
}
//use whitelist techniques to guarantee valid, non-malicious input
//with table names or column names. whitelistTableName is a function
//that YOU have to write.
$clean_table_name = whitelistTableName("track_itunes_{$cc}_total");
$insertSQL = "INSERT INTO {$clean_table_name}
(id, title, preview, track_title,
track_artist, track_amount, track_currency,
release_date, image, track_id, genre_id,
genre_cat, country, Online, Approved)
VALUES
(:id, :title, :preview, :track_title,
:track_artist, :track_amount, :track_currency,
:release_date, :image, :track_id, :genre_id,
:genre_cat, :country, :Online, :Approved)
ON DUPLICATE KEY UPDATE
title=:title_u,preview=:preview_u,track_title=:track_title_u,
track_artist=:track_artist_u,track_amount=:track_amount_u,
track_currency=:track_currency_u,release_date=:release_date_u,
image=:image_u,track_id=:track_id_u,genre_id=:genre_id_u,
genre_cat=:genre_cat_u,country=:cc_u");
$stmt = $pdo->prepare($insertSQL);
$stmt->bindValue(':id', $id);
$stmt->bindValue(':title', $title);
$stmt->bindValue(':preview', $preview);
$stmt->bindValue(':track_title', $track_title);
$stmt->bindValue(':track_artist', $track_artist);
$stmt->bindValue(':track_amount', $track_amount);
$stmt->bindValue(':track_currency', $track_currency);
$stmt->bindValue(':release_date', $release_date);
$stmt->bindValue(':image', $image);
$stmt->bindValue(':track_id', $track_id);
$stmt->bindValue(':genre_id', $genre_id);
$stmt->bindValue(':genre_cat', $genre_cat);
$stmt->bindValue(':country', $cc);
$stmt->bindValue(':Online', 1);
$stmt->bindValue(':Approved', 1);
//some drivers doesn't allow to have a named placeholder to appear more than once so we must duplicate those.
$stmt->bindValue(':id_u', $id);
$stmt->bindValue(':title_u', $title);
$stmt->bindValue(':preview_u', $preview);
$stmt->bindValue(':track_title_u', $track_title);
$stmt->bindValue(':track_artist_u', $track_artist);
$stmt->bindValue(':track_amount_u', $track_amount);
$stmt->bindValue(':track_currency_u', $track_currency);
$stmt->bindValue(':release_date_u', $release_date);
$stmt->bindValue(':image_u', $image);
$stmt->bindValue(':track_id_u', $track_id);
$stmt->bindValue(':genre_id_u', $genre_id);
$stmt->bindValue(':genre_cat_u', $genre_cat);
$stmt->bindValue(':country_u', $cc);
$stmt->bindValue(':Online_u', 1);
$stmt->bindValue(':Approved_u', 1);
$success = $stmt->execute();
if(!$success){
//something bad happened
}
}
这里有更多内容可供阅读:http://php.net/manual/en/book.pdo.php它非常简单,而且比 mysql_* 库要好得多
扩展白名单技术:有几种方法可以净化用户输入。一种是转义:这是在用户输入像文本输入一样 "open ended" 的情况下完成的,其中存在无限多种可能性。如上所示,准备好的语句对此非常完美。
另一种可能性是白名单,当用户输入的有效可能性有限(例如,单选按钮、复选框、选项选择等)并且任何无效输入都是错误或恶意时,它很有用。
示例如下:
whitelistTableName($tablename){
$allowedTables = array('tbl1', 'tbl2', 'tbl3');
if(in_array($tablename, $allowedTables)){
return $tablename;
} else {
throw new Exception('Malicious attempt detected');
}
}
这是非常基础的,但可以让您入门。更好的方法是查询您的 information_schema 数据库以获取每个有效的 table 名称,而不是手动对它们进行硬编码。