PHP警告:sprintf():参数太少

时间:2015-02-06 11:26:17

标签: php printf

我有一个运行脚本的cronjob - >从不同的iTunes商店获取数据。有时我得到上面提到的错误信息。

我认为这是因为特殊字母或类似的东西。有没有办法检查,问题到底在哪里?哪个“特殊字符”对于错误是可以解析的。例如,使用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);}

3 个答案:

答案 0 :(得分:1)

这不是sprintf的工作原理。

sprintf表示字符串printf - 您正在执行printf,它返回一个字符串而不是直接打印到stdout。

printf的工作原理是将占位符分配给格式字符串(第一个参数),并将占位符的绑定值作为后续参数。

例如

$s = sprintf("SELECT * FROM %s WHERE id = %d", 'some_table', $id);

这在某种程度上是一种简单的清理输入的方法,因为您强制使用以下格式将变量转换为某些类型:在这种情况下,%s和%d用于字符串十进制/数字,分别。在运行时,这些将被" some_table"和任何intval($ id)替换。

你得到的原因"参数太少"是因为你错过了约束值。

答案 1 :(得分:1)

我将以切向的方式回答,因为您正在使用不推荐使用的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_ *库更容易,也更好

扩展白名单技术:有几种方法可以清理用户输入。一个是逃避:这是在用户输入是"开放结束"像文本输入一样,有无限多种可能性。如上所示,准备好的陈述是完美的。

另一种可能性是白名单,当用户输入的有效可能性有限时(例如,无线电按钮,复选框,选项选择等),任何无效输入都是错误或恶意的,它很有用

示例如下:

whitelistTableName($tablename){
    $allowedTables = array('tbl1', 'tbl2', 'tbl3');
    if(in_array($tablename, $allowedTables)){
        return $tablename;
    } else {
        throw new Exception('Malicious attempt detected');
    }
}

这是非常基本的,但允许您开始使用。更好的方法是查询您的information_schema数据库以获取每个有效的表名,而不是手工硬编码。

答案 2 :(得分:-1)

首先:你应该使用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个数据库连接,则不需要提供连接链接$ con。

的mysql_query($查询);

会做到这一点。