저장할 때 확장자는 '.php'입니다.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>XML 사이트맵 생성 PHP 프로그램</title>
<meta name="robots" content="NOINDEX,NOFOLLOW">
<!-- Free Icon Fonts 읽어오기 - 사용하지 않으면 삭제 가능 -->
<link href="https://use.fontawesome.com/releases/v6.2.0/css/all.css" rel="stylesheet">
</head>
<body>
<h2> <i class="fa-regular fa-pen-to-square fa-2x" style="color: crimson"></i> XML 사이트맵 생성</h2>
<hr>
<div style="margin:15px 5px 10px 20px;padding: 0 15px 0 0; font-size: 14px;background-color: lavenderblush; border: gray 1px solid; border-radius: 4px;">
<div style="margin:15px 0 0 20px">
<form method="post">
<input type="submit" name="downloadLocal" value="XML 파일을 로컬에 다운로드" style="background-color: white;border-radius: 5px;cursor: pointer;">
</form>
</div>
<ul>
<li>여기서 다운로드한 XML 파일에는 페이지의 HTML 일부가 포함되어 있습니다.</li>
<li>참고용으로 확인하고 순수한 XML 파일이 필요한 경우 원격 서버에서 다운로드하거나, 다운로드한 파일의 HTML 부분을 삭제하세요. "<?xml version="1.0" encoding="UTF-8"?>"에서 "</urlset>"까지가 XML 파일입니다.</li>
</ul>
</div>
<hr>
<?php
//************************************************
// XML 사이트맵 생성 PHP 프로그램
// XML Sitemap Generation PHP Program
// 프로그램 제공: 모두의 지식 조금 편리한 노트
// Everyone's Knowledge A Little Useful Book
// Minna no Chishiki Chotto Benricho
// みんなの知識 ちょっと便利帳
// https://www.benricho.org/Tips/sitemapgenerator/
// 공개일: 2024년 1월 3일
//************************************************
// 웹 서버의 문서 루트. 자동 획득
$sitemapDirectory = $_SERVER['DOCUMENT_ROOT'];
// .xml 파일의 이름(최종 파일 이름)
// .xml 파일의 이름은 변경 가능하나 많은 검색 엔진이 "sitemap.xml"을 표준 명명 규칙으로 사용하므로 "sitemap.xml"을 사용하는 것이 권장됨
$finalSitemapFilename = 'sitemap.xml';
// 사이트맵 파일의 저장 위치(최종 디렉터리 - 루트)
$finalSitemapPath = $sitemapDirectory . '/' . $finalSitemapFilename;
// 사이트맵 생성 대상 디렉터리
$rootDirectory = $_SERVER['DOCUMENT_ROOT'];
// .xml 파일의 이름(임시 파일 이름)
$tempSitemapFilename = 'temporarysitemap.xml';
// 사이트맵 파일의 저장 위치(임시 디렉터리)
$tempSitemapPath = $sitemapDirectory . '/' . $tempSitemapFilename;
// 임시 디렉터리가 없으면 생성
$tempDirectory = dirname($tempSitemapPath);
if (!file_exists($tempDirectory)) {
mkdir($tempDirectory, 0777, true);
}
// 이전 사이트맵을 삭제하고 새 사이트맵으로 이름 변경(셸 명령어 사용)
$oldSitemapFilename = 'old-' . $finalSitemapFilename;
$oldSitemapPath = $sitemapDirectory . '/' . $oldSitemapFilename;
// 이전 사이트맵이 존재하는 경우 삭제
if (file_exists($oldSitemapPath)) {
unlink($oldSitemapPath);
}
// 새 사이트맵으로 이름 변경
if (file_exists($tempSitemapPath)) {
rename($tempSitemapPath, $oldSitemapPath);
}
// 로컬 다운로드 버튼이 클릭되었는지 확인
if (isset($_POST['downloadLocal'])) {
// 사이트맵을 임시 디렉터리로 복사
copy($finalSitemapPath, $tempSitemapPath);
// 다운로드용 헤더 설정
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . $finalSitemapFilename . '"');
header('Content-Length: ' . filesize($tempSitemapPath));
// 파일 출력
readfile($tempSitemapPath);
// 다운로드 후 임시 디렉터리에 저장한 사이트맵 삭제
unlink($tempSitemapPath);
exit;
}
///// 제외 대상 설정 /////
// 제외할 디렉터리. 디렉터리 이름만 지정. ['dir-1', 'dir2'] 등
// 필요하지 않으면 빈 배열. [];
$excludeDirectories = [];
// 제외할 파일. 파일 이름만 지정. ['aaa.html', 'bbb.php'] 등
// 필요하지 않으면 빈 배열. [];
$excludeFiles = [];
// 제외할 디렉터리/파일 ['dir-1/dir1/file1.html', 'dir2/file2.php'] 등
// 앞에 "/"를 추가하지 않음
// 필요하지 않으면 빈 배열. [];
$excludePaths = [];
// 메타 태그의 ['NOINDEX', 'NOFOLLOW', 'REFRESH'] 등이 포함된 파일을 제외
// 필요하지 않으면 빈 배열. [];
// ['NOINDEX']의 지정을 권장합니다
$excludeMetaTags = ['NOINDEX'];
///// 사이트맵 생성 조건 /////
// 페이지 타이틀 가져오기 (1: 가져오기, 2: 가져오지 않기)
// ※ Google Search Console에서 권장하지 않음
// ※ [중요] Google Search Console에 등록하는 경우 "2: 가져오지 않기"로 설정
// ※ "1: 가져오기"로 설정하면 Google Search Console에서 "title 태그가 인식되지 않음. 수정이 필요"라는 경고가 표시됩니다.
$getTitle = 2;
// 페이지 타이틀에서 제거할 문자열 지정
// ※ 제거하려는 문자열을 지정할 수 있습니다. ['의', '입니다'] 등
// 필요하지 않으면 비워 둡니다. [];
$removeTitleStrings = [];
// 파일의 최종 업데이트 날짜 가져오기(1: 가져오기, 2: 가져오지 않기)
// ※ Google Search Console에서 권장
$getLastMod = 1;
// 페이지 업데이트 빈도
// ※ Google에서 무시 및 비권장. '값을 추가하지 마십시오'로 명시
// 페이지 업데이트 빈도 사용(1: 사용, 2: 사용하지 않기)
$useChangeFreq = 2;
// 업데이트 빈도 요소 선택
// "1"로 설정한 경우 페이지 업데이트 빈도 요소 선택. ['always', 'hourly', 'daily', 'weekly', 'monthly', 'yearly', 'never']
// 요소 always: 매 접근마다 업데이트, hourly: 1시간마다 업데이트, daily: 매일 업데이트, weekly: 매주 업데이트, monthly: 매월 업데이트, yearly: 매년 업데이트, never: 업데이트하지 않음
$changefreqValues = ['사이트에 적용할 요소 입력'];
// 페이지 우선 순위
// ※ Google에서 무시 및 비권장. '값을 추가하지 마십시오'로 명시
// priority 가져오기(1: 가져오기, 2: 가져오지 않기)
$getPriority = 2;
// 사이트맵 생성 메시지
$successMessage = "<p>・ 사이트맵 XML 파일이 생성되었습니다.<br>・ Sitemap XML 파일이 원격 서버의 루트에 저장되었습니다.<br>・ 보안 상의 이유로 프로그램 파일을 원격 서버에서 삭제하세요.</p>";
// 사이트맵 XML 헤더(최종 파일용)
$xmlFinal = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
XML;
// 디렉터리 내의 파일을 재귀적으로 처리(최종 파일용)
function generateSitemap($directory, $excludeDirs, $excludeFiles, $getTitle, $removeTitleStrings, $getLastMod, $excludeMetaTags, $useChangeFreq, $changefreqValues, $getPriority, $excludePaths, &$xmlFinal) {
$dir = new DirectoryIterator($directory);
foreach ($dir as $fileInfo) {
if ($fileInfo->isDot()) continue;
$filename = $fileInfo->getFilename();
$filepath = $fileInfo->getPathname();
$fileExtension = pathinfo($filename, PATHINFO_EXTENSION);
// 제외 대상 디렉터리/파일 여부 확인
$excludePath = str_replace($_SERVER['DOCUMENT_ROOT'], '', $filepath);
if (in_array(ltrim($excludePath, '/'), $excludePaths)) {
continue;
}
if ($fileInfo->isDir()) {
if (in_array($filename, $excludeDirs)) {
continue;
} else {
generateSitemap($filepath, $excludeDirs, $excludeFiles, $getTitle, $removeTitleStrings, $getLastMod, $excludeMetaTags, $useChangeFreq, $changefreqValues, $getPriority, $excludePaths, $xmlFinal);
}
} else {
if (in_array($filename, $excludeFiles) || in_array($filename, $excludeDirs)) {
continue;
}
if (in_array($fileExtension, ['html', 'php'])) {
processFile($filepath, $getTitle, $removeTitleStrings, $getLastMod, $excludeMetaTags, $useChangeFreq, $changefreqValues, $getPriority, $xmlFinal);
}
}
}
}
// 파일 처리(최종 파일용)
function processFile($filepath, $getTitle, $removeTitleStrings, $getLastMod, $excludeMetaTags, $useChangeFreq, $changefreqValues, $getPriority, &$xmlFinal) {
$content = file_get_contents($filepath);
if (shouldExcludeContent($content, $excludeMetaTags)) {
return;
}
$url = getRelativeUrl($filepath);
// UTC(협정 세계 시간)로 설정 - 사이트맵 XML에서는 일반적으로 UTC(협정 세계 시간)를 사용하는 것이 권장됨
$lastMod = ($getLastMod == 1) ? getLastModifiedDateUTC($filepath) : '';
$xmlFinal .= "\n <url>";
$xmlFinal .= "\n <loc>{$url}</loc>";
if ($getTitle == 1) {
$title = getTitleFromContent($content);
if (!empty($title)) {
$title = str_replace($removeTitleStrings, '', $title);
$xmlFinal .= "\n <title>{$title}</title>";
}
}
// 마지막 업데이트 날짜 표시
if (!empty($lastMod)) {
$xmlFinal .= "\n <lastmod>{$lastMod}</lastmod>";
}
// changefreq 표시
if ($useChangeFreq == 1) {
$changefreq = $changefreqValues[array_rand($changefreqValues)];
$xmlFinal .= "\n <changefreq>{$changefreq}</changefreq>";
}
// priority 표시
if ($getPriority == 1) {
$priority = getPriorityFromDepth($filepath);
$xmlFinal .= "\n <priority>{$priority}</priority>";
}
$xmlFinal .= "\n </url>";
}
// 깊이에 따른 priority 계산(최종 파일용)
function getPriorityFromDepth($filepath) {
$depth = substr_count($filepath, DIRECTORY_SEPARATOR);
return 1 - ($depth * 0.1);
}
// 메타 태그를 제외해야 할지 확인(최종 파일용)
function shouldExcludeContent($content, $excludeMetaTags) {
foreach ($excludeMetaTags as $tag) {
if (stripos($content, '<meta name="robots" content="' . $tag) !== false) {
return true;
}
}
return false;
}
///// 파일의 최종 업데이트 날짜 가져오기 - 사이트맵 XML에서는 일반적으로 UTC(협정 세계 시간)를 사용하는 것이 권장됨
// UTC(협정 세계 시간)로 설정.('참조로부터 +00:00' 및 UTC(협정 세계 시간)으로 표시)
function getLastModifiedDateUTC($filepath) {
$lastModTimestamp = filemtime($filepath);
$lastModDateTime = new DateTimeImmutable('@' . $lastModTimestamp);
return $lastModDateTime->format('c');
}
// HTML 파일에서 제목 가져오기(최종 파일용)
function getTitleFromContent($content) {
$dom = new DOMDocument;
libxml_use_internal_errors(true); // 오류를 표시하지 않도록 설정
$dom->loadHTML($content);
$titleElements = $dom->getElementsByTagName('title');
if ($titleElements->length > 0) {
$title = $titleElements->item(0)->textContent;
return $title;
}
return '';
}
// 파일의 URL 가져오기(최종 파일용)
function getRelativeUrl($filepath) {
$relativeUrl = str_replace($_SERVER['DOCUMENT_ROOT'], '', $filepath);
return $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['SERVER_NAME'] . str_replace('\\', '/', $relativeUrl);
}
// 사이트맵 생성 시작(최종 파일용)
generateSitemap($rootDirectory, $excludeDirectories, $excludeFiles, $getTitle, $removeTitleStrings, $getLastMod, $excludeMetaTags, $useChangeFreq, $changefreqValues, $getPriority, $excludePaths, $xmlFinal);
// 사이트맵 푸터(최종 파일용)
$xmlFinal .= "\n</urlset>";
// 사이트맵을 파일에 저장(최종 파일용)
file_put_contents($finalSitemapPath, $xmlFinal);
// 성공 메시지 표시(최종 파일을 생성한 사실을 표시)
echo $successMessage;
?>
<hr>
<p style="margin-top: 20px">
<!-- <a> 태그에 이 PHP 프로그램의 파일 이름을 설정. 확장자는 ".php" -->
<a href="이 프로그램의 파일 이름.php" style="margin-left: 20px; text-decoration: none;"><i class="fa-solid fa-check" style="color: #005eff;"></i> "XML 파일" 다시 생성 <i class="fa-solid fa-rotate fa-spin fa-2x" style="color: crimson"></i>[페이지 다시로드]</a>
</p>
<p>
<!-- 생성된 "XML 파일"을 브라우저에서 열기 -->
<a href='<?php echo '/' . $finalSitemapFilename; ?>' target='_blank' style='margin-left: 20px; text-decoration: none;'><i class="fa-solid fa-check" style="color: #005eff;"></i> "XML 파일" 브라우저에서 열기 <i class="fa-solid fa-chalkboard-user fa-beat-fade fa-2x" style="color:green"></i>[새 탭]</a>
<div style="margin-left: 30px;font-size: 12px;color: gray">※ 파일 크기가 큰 경우 등 브라우저에서 열리지 않을 수 있습니다. 브라우저에서 열리지 않으면 ".xml" 파일을 웹 서버에서 다운로드하여 확인하십시오.</div>
</p>
<hr>
<!-- "Google" 사이트맵 추가 및 업데이트 확인 -->
<p>
<!-- <a> 태그에 자신의 URL을 설정 -->
<a href="https://search.google.com/search-console/sitemaps?resource_id=자신의URL" target="_blank" style="margin-left: 20px; text-decoration: none;"> <i class="fa-solid fa-check" style="color: #005eff;"></i>"<strong>Google</strong>" 사이트맵 추가 및 업데이트 확인 <i class="fa-solid fa-arrow-up-from-bracket fa-bounce fa-2x" style="color: #db0016;"></i></a>
</p>
<!-- "Google Search Console" -->
<p>
<!-- <a> 태그에 등록 한 Google Search Console의 "사이트맵"페이지 URL을 설정 -->
<a href="https://search.google.com/search-console?resource_id=자신의URL" target="_blank" style="margin-left: 20px; text-decoration: none;"><i class="fa-solid fa-check" style="color: #005eff;"></i>"<strong>Google Search Console</strong>" <i class="fa-solid fa-up-right-from-square fa-beat fa-2x" style="color: blue"></i></a>
<div style="font-size: 13px; margin: 0 40px">※ "Google Search Console"에 등록이 완료되어 있는 것이 전제되어 있습니다.</div>
</p>
<hr>
<!-- "Bing" 사이트맵 재전송 및 업데이트 확인 -->
<p>
<!-- <a> 태그에 등록 한 Bing "웹마스터 도구" 페이지 URL과 설정한 XML 파일 이름을 설정. 파일 이름은 "$sitemapFilename"으로 설정한 파일 이름과 일치해야 합니다. -->
<a href="https://www.bing.com/webmasters/sitemaps?siteUrl=자신의URL/&sitemap=자신의URL/sitemap.xml" target="_blank" style="margin-left: 20px; text-decoration: none;"> <i class="fa-solid fa-check" style="color: #005eff;"></i>"<strong>Bing</strong>" 사이트맵 재전송 및 업데이트 확인 <i class="fa-solid fa-arrow-up-from-bracket fa-bounce fa-2x" style="color: #db0016;"></i></a>
</p>
<!-- "Bing webmaster Tools" -->
<p>
<!-- <a> 태그에 등록 한 Bing "웹마스터 도구" 페이지 URL을 설정 -->
<a href="https://www.bing.com/webmasters/home?siteUrl=자신의URL" target="_blank" style="margin-left: 20px; text-decoration: none;">
<i class="fa-solid fa-check" style="color: #005eff;"></i>"<strong>Bing webmaster Tools</strong>" <i class="fa-solid fa-up-right-from-square fa-beat fa-2x" style="color: blue"></i></a>
<div style="font-size: 13px; margin: 0 40px">※ "Bing Webmaster Tools"에 등록이 완료되었거나 "Google Search Console"과 연동이 완료된 것이 전제되어 있습니다.</div>
</p>
<hr>
<!-- 자체 사이트 이름 등. 포함하지 않으면 삭제하십시오. -->
<h3 align="center"><i class="fa-solid fa-house" style="color: crimson"></i> 자체 사이트 이름 등 <i class="fa-solid fa-house" style="color: crimson"></i></h3>
<!-- 삭제해도 좋습니다. -->
<h4 align="center"><a href="https://www.benricho.org/" target="_blank" style="text-decoration: none;"><i class="fa-solid fa-house" style="color: blue"></i> 모두의 지식 조금 유용한 수첩 <i class="fa-solid fa-house" style="color: blue"></i></h4>
</body>
</html>