2015-02-06 2 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

+0

Специальный символ, вызывающий проблему, будет '%'. Sidenote 1: ваш код будет работать нормально (относительно специальной проблемы с символом), если вы не используете sprintf, а прямую строку. Sidenote 2: Этот способ построения SQL-запросов легко настраивается атаками SQL-Injection. – scones

+0

Можете ли вы привести пример, как исправить это безопасным способом? Я не «так» знаком с ним. PS. $ cc определен в коде -> но не указан в фрагменте – LJSven

ответ

1

Я отвечу тангенциально, потому что вы используете библиотеку mysql_ *, которая устарела и покажет вам PDO.Это будет: а) решить вашу проблему или 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_ * библиотеки

расширяющие на методах Whitelisting: существует несколько подходов к дезинфицировать данных, вводимых пользователем. Один из них экранируется: это делается там, где пользовательский ввод «открыт», как текстовый ввод, где есть неограниченное количество возможностей. Подготовленные утверждения идеально подходят для этого, как показано выше.

Другая возможность - это белый список, и это полезно, когда существуют только ограниченные допустимые возможности для ввода пользователя (например, радиокнопки, флажки, выбор параметров и т. Д.), А любой недопустимый ввод - либо ошибка, либо вредоносное.

пример следующим образом:

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

+0

Что это значит: «whitelistTableName - это функция // что вы должны писать. $ clean_table_name = whitelistTableName ("track_itunes _ {$ cc} _total"); " – LJSven

+0

@SvenJanning Это может показаться трудным, но на самом деле это не намного сложнее, чем функции mysql_ *. Это просто отличная нотация и подготовленные заявления. 'whitelistTableName' - это просто функция, которая сравнивает имя во вводе со списком разрешенных имен таблиц для предотвращения непреднамеренных или злых запросов. Это необходимо, потому что вы не можете использовать динамические имена таблиц в подготовленных операторах. Но 'whitelistTableName' не является родной функцией, вы должны написать это самостоятельно –

-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) 
); 

A nd для mysql_query(), вам не нужно указывать ссылку соединения $ con, если вы не используете более одного соединения с базой данных.

mysql_query ($ query);

будет делать трюк.

1

Это не так, как работает sprintf.

sprintf означает string printf - вы делаете printf, который возвращает строку вместо печати непосредственно в stdout.

printf работает, назначая заполнители в строку формата (первый аргумент) и связанные значения для заполнителей как последующие аргументы.

, например

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

Это в некотором роде наивный способ дезинфицировать ввода, поскольку вы вынуждаете переменные должны быть поданы в определенные типы, используя форматы: в этом случае% с и% D для строки и десятичные цифры/цифры, соответственно. Во время выполнения они будут заменены на «some_table» и любой intval ($ id).

Причина, по которой вы получаете «Слишком мало аргументов», заключается в том, что вам не хватает связанных значений.

+0

Можете ли вы привести пример моего кода? – LJSven

Смежные вопросы