Перейти к содержимому


Загрузка статей на сайт по Cron

mysql cron

Сообщений в теме: 15

#1 tiber

    Продвинутый пользователь

  • Пользователи
  • PipPipPip
  • 47 сообщений
Репутация: 0

Отправлено 04 Сентябрь 2019 - 22:29

Здравствуйте, коллеги!

Стоит задача - из отдельной (главной) базы MySQL, в которой находится несколько тысяч статей, надо ежедневно загружать их по крону равными "порциями", например, по 10 статей в каждую категорию БД сайта за один раз.

Загрузка должна происходить так:

В первый день с 1 по 10
Во второй день с 11 по 20
В третий день с 21 по 30
И т. д., пока не закончатся все статьи в БД.

Для этого написал скрипт, который берет указанное ему количество статей из главной БД и загружает их в БД сайта. Но загрузка происходит либо целиком всей базы сразу, либо по 10 статей с 1 по 10 в каждую категорию, если поставить brake в конце цикла.

Засада в том, что после этого, когда заново запускаю цикл (имитируя крон), загрузка начинается не с 11 статьи, а снова с 1, то есть идет повтор уже загруженных статей. Скрипт не запоминает то место, где предыдущая загрузка была остановлена при помощи brake. Подскажите, как это можно поправить!

Вот сам скрипт:


<?php
	require_once 'base/SQL.php';
	require_once 'library/config.php';

	$sql = SQL::Instance();

	//Количество категорий
	$result = mysqli_query($db, "SELECT cat FROM data");
	while($row = mysqli_fetch_assoc($result)) {
		$arr = [ ];
		$arr[ ] = $row['cat'];
	}

	$count_cat = implode('', $arr);

	//Количество всех статей в базе
	$result = mysqli_query($db, "SELECT COUNT(*) FROM data");
	$row = mysqli_fetch_array($result);
	$posts = $row[0];

	//Количество загружаемых статей
	$num = 10;

	for($start=0; $start<=$posts; $start+=10) {
		//Вывод статей из главной БД в массив $array
		for($cat=1; $cat<=$count_cat; $cat++) {
			$result = mysqli_query($db, "SELECT id, cat, title, text, author FROM data WHERE cat=$cat LIMIT $start, $num");
			while($row = mysqli_fetch_assoc($result)) {
				$array = [ ];

				$array['cat'] = $row['cat'];
				$array['title'] = $row['title'];
				$array['text'] = $row['text'];
				$array['author'] = $row['author'];

				//Запись статей из массива $array в БД сайта  
				$tobd['cat'] = $array['cat'];
				$tobd['title'] = $array['title'];
				$tobd['text'] = $array['text'];
				$tobd['author'] = $array['author'];

				$sql->Insert("data", $tobd);
			}
		}
	}
?>

Сообщение отредактировал tiber: 05 Сентябрь 2019 - 00:08


#2 matroskin8

    Администратор

  • Администраторы
  • 12 331 сообщений
Репутация: 2 111

Отправлено 05 Сентябрь 2019 - 07:03

Здравствуйте.

Просмотр сообщенияtiber (04 Сентябрь 2019 - 22:29) писал:

Скрипт не запоминает то место, где предыдущая загрузка была остановлена при помощи brake.
Получите ID последней полученной статьи из БД, в которую загружаются данные. Затем в запросе выбирайте 10 статей, ID которых больше полученного:
SELECT id, cat, title, text, author FROM data WHERE cat=$cat AND id > $id LIMIT $start, $num


#3 tiber

    Продвинутый пользователь

  • Пользователи
  • PipPipPip
  • 47 сообщений
Репутация: 0

Отправлено 05 Сентябрь 2019 - 09:54

Спасибо большое за ответ! Каким образом в PHP7 лучше вылавливать последний id,через PDO или MySQLi?

Сообщение отредактировал tiber: 05 Сентябрь 2019 - 10:15


#4 matroskin8

    Администратор

  • Администраторы
  • 12 331 сообщений
Репутация: 2 111

Отправлено 05 Сентябрь 2019 - 12:33

Просмотр сообщенияtiber (05 Сентябрь 2019 - 09:54) писал:

Спасибо большое за ответ! Каким образом в PHP7 лучше вылавливать последний id,через PDO или MySQLi?
Пожалуйста)
Получить ID можно через то расширение, с которым работаете... насколько я вижу, Вы работаете с MySQLi, поэтому логичнее через него. Ну а для получения подойдет простейший запрос:
SELECT id FROM tbl ORDER BY id DESC LIMIT 1;
или вот такой:
SELECT MAX(id) FROM tbl;


#5 tiber

    Продвинутый пользователь

  • Пользователи
  • PipPipPip
  • 47 сообщений
Репутация: 0

Отправлено 05 Сентябрь 2019 - 19:16

Этот запрос сработает корректно только в том случае, если все id идут четко по порядку, без пробелов (без дырок). Если же некоторые статьи, по разным причинам, были удалены из БД, то запрос все равно выведет номер самой последней статьи, несмотря на то, что статей фактически стало меньше. Например, последняя статья была под номером 1000, удалили из разных мест базы 20 статей, осталось 980, но запрос выведет 1000.

$res = mysqli_query($db, "SELECT id FROM data ORDER BY id DESC LIMIT 1");
$row = mysqli_fetch_assoc($res);
$id = $row['id'];
print_r($id);

Сообщение отредактировал tiber: 05 Сентябрь 2019 - 20:08


#6 matroskin8

    Администратор

  • Администраторы
  • 12 331 сообщений
Репутация: 2 111

Отправлено 06 Сентябрь 2019 - 06:53

 tiber (05 Сентябрь 2019 - 19:16) писал:

Этот запрос сработает корректно только в том случае, если все id идут четко по порядку, без пробелов (без дырок). Если же некоторые статьи, по разным причинам, были удалены из БД, то запрос все равно выведет номер самой последней статьи, несмотря на то, что статей фактически стало меньше. Например, последняя статья была под номером 1000, удалили из разных мест базы 20 статей, осталось 980, но запрос выведет 1000.
Вы путаете последний ID в таблице и количество записей. Если Вы удалите 20 статей и ID последней статьи будет 1000, тогда запрос вернет 1000. Если ID последней записи будет 980 - запрос вернет 980. Собственно последний ID и нужен, при чем здесь количество записей? Из БД, в которую импортируются данные, получается последний ID - он и будет тем, с которого нужно начать выборку из источника.

#7 tiber

    Продвинутый пользователь

  • Пользователи
  • PipPipPip
  • 47 сообщений
Репутация: 0

Отправлено 06 Сентябрь 2019 - 10:44

Понятно, дырки не имеют значения!

Проще говоря, не совсем ясно куда прикрутить этот запрос. Все встанет на свои места, если Вы просто пальцем покажете куда прописать его в скрипте, а то пока не совсем четко себе это представляю.

#8 matroskin8

    Администратор

  • Администраторы
  • 12 331 сообщений
Репутация: 2 111

Отправлено 06 Сентябрь 2019 - 15:30

 tiber (06 Сентябрь 2019 - 10:44) писал:

Проще говоря, не совсем ясно куда прикрутить этот запрос.
Насколько я понял Ваш код, то выборка из БД-донора происходит в этом запросе:
$result = mysqli_query($db, "SELECT id, cat, title, text, author FROM data WHERE cat=$cat LIMIT $start, $num");
Соответственно, вот перед ним, точнее, перед циклом for нужно выполнить запрос к БД-реципиенту и получить конечный ID, чтобы этот ID использовать в Вашем запросе выше. Но здесь нужно помнить, что у Вас зачем-то используется цикл for и все запросы крутятся в нем и добавив в условие конечный ID с которого нужно осуществлять выборку, нужно с каждой итерацией цикла инкрементировать ID... но в этом случае "дыры" в последовательности записей донора как раз могут играть негативную роль. Поэтому я бы убрал цикл, он здесь, как мне кажется, абсолютно не нужен. Логика работы скрипта должна быть примерно такой:
// получаем конечный ID из реципиента
$query = SELECT MAX(id) FROM tbl;
...
// используем полученный ID для выборки из донора
// на этом этапе у нас уже будет 10 статей и цикл абсолютно лишний
$result = mysqli_query($db, "SELECT id, cat, title, text, author FROM data WHERE cat=$cat AND id > $id LIMIT $start, $num");
while($row = mysqli_fetch_assoc($result)) {
    // здесь можно либо сформировать 1 sql-запрос на вставку данных, либо уже в цикле вставить каждую строку, если удобнее так
}


#9 tiber

    Продвинутый пользователь

  • Пользователи
  • PipPipPip
  • 47 сообщений
Репутация: 0

Отправлено 06 Сентябрь 2019 - 21:38

Спасибо большое за подробное объяснение, теперь картинка сложилась полностью!

Насчет первого цикла for() с переменной $start я с Вами согласен, что он здесь лишний. Им я пытался установить стартовые позиции для вывода статей по десяткам, но это не сработало. Насчет второго цикла for() с переменно $cat думаю он здесь нужен, так как подставляет в запрос категории.

Желаю удачи и успехов! :rolleyes:

#10 matroskin8

    Администратор

  • Администраторы
  • 12 331 сообщений
Репутация: 2 111

Отправлено 07 Сентябрь 2019 - 06:08

Пожалуйста ;)

#11 tiber

    Продвинутый пользователь

  • Пользователи
  • PipPipPip
  • 47 сообщений
Репутация: 0

Отправлено 08 Сентябрь 2019 - 19:45

Снова здравствуйте!

Появилась небольшая проблема. Когда с помощью PDO пытаюсь вывести ID статьи, то ошибок не показывает, но и ничего не выводится, ни в foreach(), ни в while(). Посмотрите, пожалуйста, в чем ошибка, а то в ООП опыт у меня пока еще небольшой. На всякий случай выкладываю PDOшный файл SQL.php (брал его уже готовым), который используется для загрузки статей, взятых из базы-донора в базу-реципиента. Внутренний голос подсказывает, что его также можно использовать и для вывода ID, но возможно я ошибаюсь.

Вот итоговый скрипт:

<?php
	require_once 'server/SQL.php';
	require_once 'library/config.php';

	$sql = SQL::Instance();

	//Количество категорий
	$result = mysqli_query($db, "SELECT cat FROM data");
	while($row = mysqli_fetch_assoc($result)) {
		$count_cat =$row['cat'];
	}

	//Вывод ID
	try {
		$pdo = new PDO('mysql:host=localhost; dbname=base', 'login', '12345');
		$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

		$sql = "SELECT id FROM data ORDER BY id DESC LIMIT 1";
		$res = $pdo->query($sql);

		foreach($res as $row) {
			$id = $row['id'];
			//echo $id;
			//print_r($id);
		}

		while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
			$id = $row['id'];
			//echo $id;
			//print_r($id);
		}
	}

	catch(PDOException $e) {
		echo $e->getMessage();
	}

	//Вывод статей из главной БД в массив $array
	for($cat=1; $cat<=$count_cat; $cat++) {
		$result = mysqli_query($db, "SELECT id, cat, title, text, author FROM data WHERE cat = $cat AND id > $id LIMIT $id, 10");
		while($row = mysqli_fetch_assoc($result)) {
			$array = [ ];

			$array['cat'] = $row['cat'];
			$array['title'] = $row['title'];
			$array['text'] = $row['text'];
			$array['author'] = $row['author'];	

			//Запись статей из массива $array в БД сайта  
			$tobd['cat'] = $array['cat'];
			$tobd['title'] = $array['title'];
			$tobd['text'] = $array['text'];
			$tobd['author'] = $array['author'];

			$sql->Insert("data", $tobd);
		}
	}
?>

Файл SQL.php

<?php
	class SQL {
		private static $instance;
		private $db;

		public static function Instance() {
			if(self::$instance == null) {
				self::$instance = new SQL();
			}

			return self::$instance;
		}

		private function __construct() {
			setlocale(LC_ALL, 'ru_RU.UTF8');
			$this->db = new PDO('mysql:host=localhost; dbname=base', 'login', '12345');
			$this->db->exec('SET NAMES UTF8');
			$this->db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
		}

		public function Select($query) {
			$q = $this->db->prepare($query);
			$q->execute();

			if($q->errorCode() != PDO::ERR_NONE) {
				$info = $q->errorInfo();
				die($info[2]);
			}

			return $q->fetchAll();
		}

		public function Insert($table, $object) {
			$columns = array();

			foreach($object as $key => $value) {

				$columns[ ] = $key;
				$masks[ ] = ":$key";

				if($value === null) {
					$object[$key] = 'NULL';
				}
			}

			$columns_s = implode(',', $columns);
			$masks_s = implode(',', $masks);

			$query = "INSERT INTO $table ($columns_s) VALUES ($masks_s)";

			$q = $this->db->prepare($query);
			$q->execute($object);

			if($q->errorCode() != PDO::ERR_NONE) {
				$info = $q->errorInfo();
				die($info[2]);
			}

			return $this->db->lastInsertId();
		}

		public function Update($table, $object, $where) {
			$sets = array();

			foreach($object as $key => $value) {

				$sets[ ] = "$key=:$key";

				if($value === NULL) {
					$object[$key]='NULL';
				}
			}

			$sets_s = implode(',',$sets);
			$query = "UPDATE $table SET $sets_s WHERE $where";

			$q = $this->db->prepare($query);
			$q->execute($object);

			if($q->errorCode() != PDO::ERR_NONE) {
				$info = $q->errorInfo();
				die($info[2]);
			}

			return $q->rowCount();
		}

		public function Delete($table, $where) {
			$query = "DELETE FROM $table WHERE $where";
			$q = $this->db->prepare($query);
			$q->execute();

			if($q->errorCode() != PDO::ERR_NONE) {
				$info = $q->errorInfo();
				die($info[2]);
			}

			return $q->rowCount();
		}
	}
?>

Сообщение отредактировал tiber: 08 Сентябрь 2019 - 20:52


#12 matroskin8

    Администратор

  • Администраторы
  • 12 331 сообщений
Репутация: 2 111

Отправлено 09 Сентябрь 2019 - 06:27

Здравствуйте.
Вот такой вариант должен вернуть ID:
$sql = "SELECT id FROM data ORDER BY id DESC LIMIT 1";
$res = $pdo->query($sql);
foreach($res as $row) {
    echo $id = $row['id']; // на экране должны увидеть ID
}


#13 tiber

    Продвинутый пользователь

  • Пользователи
  • PipPipPip
  • 47 сообщений
Репутация: 0

Отправлено 09 Сентябрь 2019 - 09:32

Именно такой вариант прописан в моем скрипте, только с проверкой на ошибки, но что с ней, что без нее - выводится сообщение, что ID не определен:
Notice: Undefined variable: id in /var/www/html/server.php on line 53

Сообщение отредактировал tiber: 09 Сентябрь 2019 - 09:35


#14 matroskin8

    Администратор

  • Администраторы
  • 12 331 сообщений
Репутация: 2 111

Отправлено 09 Сентябрь 2019 - 10:05

Просмотр сообщенияtiber (09 Сентябрь 2019 - 09:32) писал:

Именно такой вариант прописан в моем скрипте, только с проверкой на ошибки, но что с ней, что без нее - выводится сообщение, что ID не определен:
Notice: Undefined variable: id in /var/www/html/server.php on line 53
Проверил только что у себя этот вариант - без проблем получаю ID. Очевидно, где-то есть проблема в Вашем коде.
А зачем Вы одновременно используете и PDO и MySQLi? Теоретически проблем-то быть не должно, но с практической стороны это выглядит достаточно странно и нерационально, поскольку вместо одного подключения Вы устанавливаете два. Я бы все же рекомендовал использовать что-то одно, в этом случае и вероятность путаницы будет меньше.

#15 tiber

    Продвинутый пользователь

  • Пользователи
  • PipPipPip
  • 47 сообщений
Репутация: 0

Отправлено 09 Сентябрь 2019 - 11:41

Так как скрипт одновременно работает с двумя базами (донором и реципиентом), то PDO и MySQLi используются для того, чтобы избежать конфликта между конфигурационными файлами подключения к каждой из этих баз. Если использовать только MySQLi и в одном скрипте подключить первый конфиг к базе-донору, а второй к базе-реципиенту, то между ними происходит конфликт. Пробовал так делать, но вылезает ошибка подключения. Поэтому MySQLi скачивает данные с базы-донора, а PDOшный файл SQL.php записывает их в базу-реципиента.

Если надо скачать и загрузить всю базу целиком, то скрипт без проблем за несколько секунд справляется с этой задачей, так как в этом случае на требуется вывод последнего ID. Но когда надо скачать и загрузить статьи "порциями", например, по 10 за один запуск скрипта, тут и возникла ошибка с выводом последнего ID из базы-реципиента.

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

Сообщение отредактировал tiber: 09 Сентябрь 2019 - 11:47


#16 matroskin8

    Администратор

  • Администраторы
  • 12 331 сообщений
Репутация: 2 111

Отправлено 09 Сентябрь 2019 - 13:21

Просмотр сообщенияtiber (09 Сентябрь 2019 - 11:41) писал:

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





Количество пользователей, читающих эту тему: 1

0 пользователей, 1 гостей, 0 анонимных