Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
Base.php
1<?php
9
15
19class Base extends File
20{
21 const XML_HEADER = '<?xml version="1.0" encoding="UTF-8"?>';
22
23 const FILE_HEADER = '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">';
24 const FILE_FOOTER = '</urlset>';
25
26 const ENTRY_TPL = '<url><loc>%s</loc><lastmod>%s</lastmod></url>';
27 const ENTRY_TPL_SEARCH = '<url><loc>%s</loc>';
28
29 const XPATH_URL = '/urlset/url';
30
31 const MAX_SIZE = 5000000;
32
33 const FILE_EXT = '.xml';
34 const FILE_PART_SUFFIX = '.part';
35
36 protected $documentRoot;
37 protected $settings = array();
38 protected $parser = false;
39
40 protected $siteRoot = '';
41 protected $partFile = '';
42 protected array $partList = [];
43 protected int $part = 0;
44 protected bool $partChanged = false;
45 protected bool $footerClosed = false;
46
47 protected $urlToSearch = '';
48 protected $urlFound = false;
49
50 public function __construct($fileName, $settings)
51 {
52 $this->settings = [
53 'SITE_ID' => $settings['SITE_ID'],
54 'PROTOCOL' => $settings['PROTOCOL'] == 'https' ? 'https' : 'http',
55 'DOMAIN' => $settings['DOMAIN'],
56 ];
57
58 $site = SiteTable::getRow(["filter" => ["LID" => $this->settings['SITE_ID']]]);
59
60 $this->documentRoot = SiteTable::getDocumentRoot($this->settings['SITE_ID']);
61 $this->footerClosed = false;
62
63 $this->siteRoot = Path::combine(
64 $this->documentRoot,
65 $site['DIR']
66 );
67
68 $fileName = $this->prepareFileName($fileName);
69 $this->partFile = $this->partFile ?: $fileName;
70 $this->pathPhysical = null; // hack for object reconstuct during file splitting
71 parent::__construct($this->siteRoot.'/'.$fileName, $this->settings['SITE_ID']);
72 $this->partChanged = $this->isExists() && !$this->isSplitNeeded();
73 }
74
75 protected function prepareFileName($fileName)
76 {
77 // normalize slashes
78 $fileName = Path::normalize($fileName);
79 if (mb_substr($fileName, -mb_strlen(self::FILE_EXT)) != self::FILE_EXT)
80 {
81 $fileName .= self::FILE_EXT;
82 }
83
84 // convert words delimiter, google dont't like '_''
85 $fileName = str_replace('_', '-', $fileName);
86
87 return $fileName;
88 }
89
95 protected function reInit($fileName)
96 {
97 $this->__construct($fileName, $this->settings);
98 }
99
105 public function addHeader()
106 {
107 $this->partChanged = true;
108 $this->putContents(self::XML_HEADER.self::FILE_HEADER);
109 }
110
117 protected function isSplitNeeded()
118 {
119 return $this->isExists() && $this->getSize() >= self::MAX_SIZE;
120 }
121
133 public function addEntry($entry)
134 {
135 if ($this->isSplitNeeded())
136 {
137 $this->split();
138 $this->addEntry($entry);
139 }
140 else
141 {
142 if (!$this->partChanged)
143 {
144 $this->addHeader();
145 }
146
147 $this->putContents(
148 sprintf(
149 self::ENTRY_TPL,
150 Converter::getXmlConverter()->encode($entry['XML_LOC']),
151 Converter::getXmlConverter()->encode($entry['XML_LASTMOD'])
152 ), self::APPEND
153 );
154 }
155 }
156
162 public function split()
163 {
164 if($this->partChanged)
165 {
166 $this->addFooter();
167 }
168
169 $this->partList[] = $this->getName();
170 $this->part++;
171
172 $fileName = $this->partFile;
173 $fileName = mb_substr($fileName, 0, -mb_strlen(self::FILE_EXT)).self::FILE_PART_SUFFIX.$this->part.mb_substr($fileName, -mb_strlen(self::FILE_EXT));
174
175 $this->reInit($fileName);
176
177 $this->partChanged = $this->isExists() && !$this->isSplitNeeded();
178
179 return $fileName;
180 }
181
187 public function getNameList()
188 {
189 return $this->isCurrentPartNotEmpty() ? array_merge($this->partList, array($this->getName())) : $this->partList;
190 }
191
196 public function getPathDirectory(): string
197 {
198// normalize slashes
199 $siteRoot = Path::normalize($this->siteRoot);
200 $fileName = $this->getName();
201 $path = Path::normalize($this->path);
202
203 $directory = str_replace(array($siteRoot, $fileName), array('',''), $path);
204
205 return ltrim($directory, '/');
206 }
207
213 public function isNotEmpty()
214 {
215 return (count($this->partList) > 0) || $this->isCurrentPartNotEmpty();
216 }
217
223 public function isCurrentPartNotEmpty()
224 {
225 if($this->isExists())
226 {
227 $c = $this->getContents();
228 return $c <> '' && $c != self::XML_HEADER.self::FILE_HEADER;
229 }
230
231 return false;
232 }
233
245 public function appendEntry($entry)
246 {
247 if ($this->isSplitNeeded())
248 {
249 $this->split();
250 $this->appendEntry($entry);
251 }
252 else
253 {
254 if(!$this->partChanged)
255 {
256 $this->addHeader();
257 $offset = $this->getSize();
258 }
259 else
260 {
261 $offset = $this->getSize() - mb_strlen(self::FILE_FOOTER);
262 }
263
264 $fd = $this->open('r+');
265
266 fseek($fd, $offset);
267 fwrite($fd, sprintf(
268 self::ENTRY_TPL,
269 Converter::getXmlConverter()->encode($entry['XML_LOC']),
270 Converter::getXmlConverter()->encode($entry['XML_LASTMOD'])
271 ).self::FILE_FOOTER);
272 fclose($fd);
273
274 $this->footerClosed = true;
275 }
276 }
277
289 public function removeEntry($url)
290 {
291 $fileName = $this->partFile;
292 $e = [];
293 $url = $this->settings['PROTOCOL'] . '://' . \CBXPunycode::toASCII($this->settings['DOMAIN'], $e) . $url;
294 $pattern = sprintf(self::ENTRY_TPL_SEARCH, $url);
295
296 while($this->isExists())
297 {
298 $c = $this->getContents();
299 $p = mb_strpos($c, $pattern);
300 unset($c);
301
302 if($p !== false)
303 {
304 $fd = $this->open('r+');
305
306 fseek($fd, intval($p));
307 fwrite($fd, str_repeat(" ", mb_strlen(sprintf(
308 self::ENTRY_TPL,
309 Converter::getXmlConverter()->encode($url),
310 Converter::getXmlConverter()->encode(date('c'))
311 ))));
312 fclose($fd);
313 break;
314 }
315
316 if(!$this->isSplitNeeded())
317 {
318 break;
319 }
320 else
321 {
322 $this->part++;
323 $fileName = mb_substr($fileName, 0, -mb_strlen(self::FILE_EXT)).self::FILE_PART_SUFFIX.$this->part.mb_substr($fileName, -mb_strlen(self::FILE_EXT));
324 $this->reInit($fileName);
325 }
326 }
327
328 return $fileName;
329 }
330
339 public function addFileEntry(File $f): void
340 {
341 if ($f->isExists() && !$f->isSystem())
342 {
343 $e = [];
344 $this->addEntry([
345 'XML_LOC' =>
346 $this->settings['PROTOCOL']
347 . '://'
348 . \CBXPunycode::toASCII($this->settings['DOMAIN'], $e)
349 . $this->getFileUrl($f)
350 ,
351 'XML_LASTMOD' => date('c', $f->getModificationTime()),
352 ]);
353 }
354 }
355
364 public function addIBlockEntry($url, $modifiedDate)
365 {
366 $e = [];
367 $this->addEntry([
368 'XML_LOC' =>
369 $this->settings['PROTOCOL']
370 . '://'
371 . \CBXPunycode::toASCII($this->settings['DOMAIN'], $e)
372 . $url
373 ,
374 'XML_LASTMOD' => date('c', $modifiedDate - \CTimeZone::getOffset()),
375 ]);
376 }
377
386 public function appendIBlockEntry($url, $modifiedDate)
387 {
388 if ($this->isExists())
389 {
390 $e = [];
391 $this->appendEntry([
392 'XML_LOC' =>
393 $this->settings['PROTOCOL']
394 . '://'
395 . \CBXPunycode::toASCII($this->settings['DOMAIN'], $e)
396 . $url
397 ,
398 'XML_LASTMOD' => date('c', $modifiedDate - \CTimeZone::getOffset()),
399 ]);
400 }
401 else
402 {
403 $this->addHeader();
404 $this->addIBlockEntry($url, $modifiedDate);
405 $this->addFooter();
406 }
407 }
408
414 public function addFooter()
415 {
416 $this->putContents(self::FILE_FOOTER, self::APPEND);
417 $this->footerClosed = true;
418 }
419
425 public function getSiteRoot()
426 {
427 return $this->siteRoot;
428 }
429
435 public function getUrl()
436 {
437 $e = [];
438 return $this->settings['PROTOCOL'].'://'.\CBXPunycode::toASCII($this->settings['DOMAIN'], $e).$this->getFileUrl($this);
439 }
440
447 public function parse()
448 {
449 if(!$this->parser)
450 {
451 if($this->isExists())
452 {
453 $this->parser = new \CDataXML();
454 $this->parser->loadString($this->getContents());
455 }
456 }
457
458 return $this->parser;
459 }
460
468 protected function getFileUrl(File $f)
469 {
470 static $indexNames;
471 if(!is_array($indexNames))
472 {
473 $indexNames = GetDirIndexArray();
474 }
475
476 $documentRoot = Path::normalize($this->documentRoot);
477 $path = '/';
478 if (mb_substr($this->path, 0, mb_strlen($documentRoot)) === $documentRoot)
479 {
480 $path = '/'.mb_substr($f->getPath(), mb_strlen($documentRoot));
481 }
482
484
485 $path = in_array($f->getName(), $indexNames)
486 ? str_replace('/'.$f->getName(), '/', $path)
487 : $path;
488
489 return '/'.ltrim($path, '/');
490 }
491}
putContents($data, $flags=self::REWRITE)
Definition file.php:65
$path
getPath()
getName()
isSystem()
static normalize($path)
Definition path.php:26
static convertLogicalToUri($path)
Definition path.php:142
static combine()
Definition path.php:221
addIBlockEntry($url, $modifiedDate)
Definition Base.php:364
prepareFileName($fileName)
Definition Base.php:75
appendIBlockEntry($url, $modifiedDate)
Definition Base.php:386
__construct($fileName, $settings)
Definition Base.php:50