2015-02-06 123 views
1

我有一個運行腳本的cronjob - >從不同的iTunes商店獲取數據。有時候我會收到上面提到的錯誤信息。PHP警告:sprintf():參數太少

我認爲它是因爲特殊字母或類似的東西。有沒有辦法檢查問題的確切位置?哪個「特殊字符」可以對錯誤進行抑制。 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);} 
+1

爲什麼你也使用'sprintf()'也定義了$ cc'? – Rizier123 2015-02-06 11:27:46

+0

導致問題的特殊字符是'%'。旁註1:如果你不使用sprintf,而是直接使用字符串,你的代碼可以正常工作(關於特殊字符問題)。旁註2:構建SQL-Queries的這種方式很容易被SQL注入攻擊所攻擊。 – scones 2015-02-06 11:31:54

+0

你能舉一個例子如何以安全的方式解決它嗎?我不是「那麼」熟悉它。 PS。 $ cc在代碼中定義 - >但在代碼段 – LJSven 2015-02-06 11:40:40

回答

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數據庫以獲取每個有效的表名,而不是手動對其進行硬編碼。

+0

對你來說很簡單...說實話...我不知道,我可以或必須從這裏開始...... – LJSven 2015-02-06 13:22:03

+0

這是什麼意思「whitelistTableName是一個函數 //你必須寫 $ clean_table_name = whitelistTableName(「track_itunes _ {$ cc} _total」);「 – LJSven 2015-02-06 14:43:30

+0

@SvenJanning這似乎很難,但實際上它並不比mysql_ *函數難多少。這只是一種不同的記法和準備的陳述。 'whitelistTableName'只是一個函數,它將輸入中的名稱與允許的表名列表進行比較,以防止無意或無意的查詢。這是必需的,因爲您不能在預準備語句中使用動態表名稱。但是'whitelistTableName'不是一個本地函數,你必須自己編寫它 – 2015-02-06 15:49:59

-1

第一:因爲MySQL是不贊成你應該使用mysql_real_escape_string(),甚至更好地利用mysqli的,而不是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) 
); 

A nd對於mysql_query(),如果不使用多於1個數據庫連接,則不需要提供連接鏈接$ con。

mysql_query($ query);

將做的伎倆。

1

這不是sprintf的工作原理。

sprintf意味着字符串printf - 你正在做一個printf返回一個字符串,而不是直接打印到標準輸出。

printf通過將佔位符分配給格式字符串(第一個參數),並將佔位符的邊界值作爲後續參數來工作。

例如

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

這在某種程度上淨化輸入,因爲你正迫使變量被丟在使用格式某些類型的一個簡單的方式:在這種情況下,%s和%d的十進制/數字。在運行時,這些將被替換爲「some_table」,無論intval($ id)是什麼。

您得到「參數太少」的原因是因爲您缺少綁定值。

+0

您可以舉例說明我的代碼嗎? – LJSven 2015-02-06 11:45:44