Joywork/admin/migrate-articles.php
2026-05-22 21:21:54 +03:00

206 lines
9.1 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
require_once($_SERVER['DOCUMENT_ROOT'] . "/config.php");
if (!$_SESSION['superadmin']) { die('Доступ запрещён'); }
// Карта id → slug (из существующих PHP-заглушек)
$slugMap = [
1 => 'poisk-obektov-nedvizhimosti-scanner',
2 => 'multilistingovaya-sistema-partnerskikh-sdelok',
3 => 'voronki-prodazh-v-crm',
4 => 'avtopublikaciya-obyavlenij-na-200-sajtov',
5 => 'ip-telefoniya-i-kolltraking-v-crm',
6 => 'dokumentooborot-v-crm-dlja-rieltorov',
7 => 'baza-kommercheskoj-nedvizhimosti',
8 => 'kabinet-klienta-v-crm',
9 => 'odobrjaem-ipoteku-onlajn-broker',
10 => 'skvoznaja-analitika-v-nedvizhimosti',
11 => 'reklama-kvartiry-v-socsetyah',
12 => 'crm-dlja-agenta-reklama-200-sajtov',
13 => 'poisk-obektov-na-tematicheskih-sajtah',
14 => 'smart-voronka-prodazh-v-crm',
15 => 'integraciya-crm-s-ip-telefoniej',
16 => 'zakaz-svedenij-egrn-iz-crm',
17 => 'nakoplenie-klientskoj-bazy-targetirovannaya-reklama',
18 => 'dokumentooborot-rieltora-v-crm',
19 => 'avtomaticheskij-poisk-v-crm',
20 => 'upravlenie-tipami-razmeshchenij-obektov',
21 => 'internet-marketing-v-nedvizhimosti',
22 => 'kak-reklamirovat-nedvizhimost-na-ploshchadkah',
23 => 'strategii-prodvizheniya-agentstva-2023',
24 => 'analiz-rynka-rijeltorskih-uslug',
25 => 'servisy-po-poisku-nedvizhimosti',
26 => 'marketing-dlja-zastrojshhikov',
27 => 'analiz-obektov-nedvizhimosti',
28 => 'prezentacija-obektov-nedvizhimosti',
29 => 'parser-nedvizhimosti',
30 => 'poisk-obektov-nedvizhimosti-v-rezhime-online',
31 => 'kak-uvelichit-prodazhi-nedvizhimosti',
32 => 'na-kakih-sajtah-prodavat-nedvizhimost',
33 => 'avtomatizacija-prodazh-nedvizhimosti',
34 => 'instrumenty-rijeltora-nedvizhimosti',
35 => 'lidy-dlja-agentstva-nedvizhimosti',
36 => 'cel-vnedrenija-crm',
37 => 'rijeltor-nedvizhimosti-s-nulja',
38 => 'houmstejdzhing-kvartiry',
39 => 'prognoz-rynka-nedvizhimosti-2024',
40 => 'otchet-rijeltora-o-rabote',
41 => 'baza-novostroek-ot-zastrojshhika',
42 => 'klienty-na-nedvizhimost',
43 => 'opredelit-rynochnuju-stoimost-obekta',
44 => 'avtovygruzka-nedvizhimosti-na-avito',
45 => 'kak-otkryt-agentstvo-nedvizhimosti',
46 => 'flipping-v-nedvizhimosti',
47 => 'cifrovye-tehnologii-v-nedvizhimosti',
48 => 'cenoobrazovanie-na-rynke-nedvizhimosti',
49 => 'crm-sdelki-s-nedvizhimostju',
50 => 'upravlenie-reklamnymi-kampanijami',
51 => 'marketing-dlja-zastrojshhikov-vazhnost',
52 => 'srm-dlja-stroitelnoj-kompanii',
53 => 'kak-rijeltoru-najti-klientov',
54 => 'sajt-dlja-agentstva-nedvizhimosti',
55 => 'brend-agentstva-nedvizhimosti',
56 => 'reklama-dlja-rijeltora',
57 => 'franshiza-agentstva-nedvizhimosti',
58 => 'skript-holodnogo-zvonka',
59 => 'biznes-plan-agentstva-nedvizhimosti',
60 => 'struktura-agentstva-nedvizhimosti',
61 => 'oshibki-pri-vnedrenii-crm',
62 => 'cifrovizacija-nedvizhimosti',
63 => 'segmentacija-klientov-srm',
64 => 'utp-dlja-nedvizhimosti',
65 => 'avtomatizacija-raboty-rieltora',
66 => 'avtomatizaciya-otdela-prodazh-nedvizhimosti',
67 => 'otsenka-kvartiry-brokerom',
68 => 'servis-dlya-analiza-nedvizhimosti',
];
$src = file_get_contents($_SERVER['DOCUMENT_ROOT'] . '/article.php');
// Извлекаем скалярные поля метаданных через regex (без eval)
function extractArtField($src, $id, $field) {
if (preg_match('/\$art' . $id . '\[\'' . $field . '\'\]\s*=\s*"([^"]*?)"/u', $src, $m)) return $m[1];
if (preg_match("/\\\$art{$id}\\['{$field}'\\]\\s*=\\s*'([^']*?)'/u", $src, $m)) return $m[1];
return '';
}
function extractArtAuthorField($src, $id, $field) {
if (preg_match('/\$art' . $id . '\[\'author\'\]\s*=\s*\[.*?\'' . $field . '\'\s*=>\s*\'([^\']*?)\'/su', $src, $m)) return $m[1];
if (preg_match('/\$art' . $id . '\[\'author\'\]\s*=\s*\[.*?\'' . $field . '\'\s*=>\s*"([^"]*?)"/su', $src, $m)) return $m[1];
return '';
}
// Извлекаем HTML-контент из блоков if ($id == X) { ... }
function extractArtContent($src, $id) {
if (preg_match('/\$id == ' . $id . '\) \{ \?>(.*?)(?=<\?php \})/su', $src, $m)) {
return trim($m[1]);
}
return '';
}
function convertDate($d) {
$parts = explode('.', $d);
if (count($parts) === 3) return $parts[2] . '-' . $parts[1] . '-' . $parts[0];
return date('Y-m-d');
}
// Генерируем description из первого абзаца статьи (для SEO и карточек блога)
function generateDescription($content) {
if (!$content) return '';
// Берём первый <p> в статье
if (preg_match('/<p[^>]*>(.*?)<\/p>/s', $content, $m)) {
$text = strip_tags($m[1]);
$text = preg_replace('/\s+/u', ' ', $text);
$text = trim(html_entity_decode($text, ENT_QUOTES, 'UTF-8'));
// Обрезаем до ~160 символов (стандарт meta description), не разрезая слова
if (mb_strlen($text, 'UTF-8') > 160) {
$text = mb_substr($text, 0, 160, 'UTF-8');
$lastSpace = mb_strrpos($text, ' ', 0, 'UTF-8');
if ($lastSpace !== false) $text = mb_substr($text, 0, $lastSpace, 'UTF-8');
$text .= '…';
}
return $text;
}
return '';
}
// Считаем количество <script> блоков в контенте (для отчёта в dry-run)
function countScripts($content) {
return preg_match_all('/<script[\s\S]*?<\/script>/i', $content);
}
$dryRun = isset($_GET['dry']) && $_GET['dry'] == '1';
$results = [];
$errors = [];
for ($i = 1; $i <= 68; $i++) {
$title = extractArtField($src, $i, 'title');
if (!$title) {
$errors[] = "Нет title для статьи #$i";
continue;
}
$slug = isset($slugMap[$i]) ? $slugMap[$i] : Article::makeSlug($title);
$content = extractArtContent($src, $i);
$dateRaw = extractArtField($src, $i, 'date');
$updateRaw = extractArtField($src, $i, 'update');
$data = [
'slug' => $slug,
'title' => $title,
'page_title' => extractArtField($src, $i, 'pageTitle') ?: $title,
'description' => generateDescription($content),
'content' => $content,
'date_created' => $dateRaw ? convertDate($dateRaw) : date('Y-m-d'),
'date_updated' => $updateRaw ? convertDate($updateRaw) : date('Y-m-d'),
'reading_time' => max(1, (int)extractArtField($src, $i, 'time')),
'image' => extractArtField($src, $i, 'image'),
'author_name' => extractArtAuthorField($src, $i, 'name') ?: 'Станислав Дмитриев',
'author_img' => extractArtAuthorField($src, $i, 'img') ?: '/images/articles/rukofodJW.png',
'author_job' => extractArtAuthorField($src, $i, 'job') ?: 'руководитель JoyWork',
'published' => 1,
'sort_order' => $i,
];
$scriptsCount = countScripts($content);
if (!$dryRun) {
if (!Article::slugExists($slug)) {
Article::create($data);
$scriptsNote = $scriptsCount > 0 ? " | scripts: {$scriptsCount}" : '';
$results[] = "✓ #{$i}: {$title}{$scriptsNote}";
} else {
$results[] = "— #{$i}: пропущена (slug уже есть): {$slug}";
}
} else {
$contentInfo = strlen($content) ? strlen($content) . " симв." : '❌ пусто';
$scriptsInfo = $scriptsCount > 0 ? " | scripts: {$scriptsCount}" : '';
$descrInfo = $data['description'] ? ' | descr: ✓' : ' | descr: ❌';
$results[] = "[DRY] #{$i}: {$title}{$slug} | контент: {$contentInfo}{$scriptsInfo}{$descrInfo}";
}
}
?><!DOCTYPE html>
<html><head><meta charset="utf-8"><title>Миграция статей</title>
<style>body{font-family:Arial;padding:20px;max-width:900px;} .ok{color:green;} .err{color:red;} pre{background:#f5f5f5;padding:15px;border-radius:4px;font-size:13px;line-height:1.6;white-space:pre-wrap;}</style>
</head><body>
<h2>Миграция статей из PHP в БД</h2>
<?php if ($dryRun): ?>
<p style="background:#fff3cd;padding:10px;border-radius:4px;">⚠️ Режим dry-run — данные <strong>не записаны</strong>. Проверьте результаты и <a href="?">запустите реально</a>.</p>
<?php else: ?>
<p><a href="?dry=1">Dry-run (без записи)</a> | <a href="/admin/articles.php">← К списку статей</a></p>
<?php endif; ?>
<h3>Результат (<?= count($results) ?> / 68):</h3>
<pre><?php foreach ($results as $r) echo htmlspecialchars($r) . "\n"; ?></pre>
<?php if ($errors): ?>
<h3 class="err">Ошибки (<?= count($errors) ?>):</h3>
<pre class="err"><?php foreach ($errors as $e) echo htmlspecialchars($e) . "\n"; ?></pre>
<?php endif; ?>
<?php if (!$dryRun && empty($errors) && count($results) > 0): ?>
<p class="ok" style="font-size:16px;"><strong>✓ Готово! <a href="/admin/articles.php">Перейти к статьям →</a></strong></p>
<?php endif; ?>
</body></html>