nginxで画像が見つからない時に代替画像を表示する

2024/01/05 (金) - 00:00 Server

とある作品ギャラリーのWebページ制作依頼で、img要素等で表示する作品の画像ファイルが見つからなかったとき代替画像を表示させたいという要望がありました。以下は例です。

<img src="img/test.png" alt="PNG画像" />
<hr />
<img src="img/test.jpg" alt="JPEG画像" />

画像が存在するときは正常に画像が表示されます。

正常な画像表示

画像ファイルがサーバから消えたり見つからず、404エラーとなった時のブラウザ表示。

エラー画像表示

エラーではなく代替画像を表示させるため、nginxのnginx.confに以下を設定しました。代替表示させる画像ファイルはあらかじめ用意しておき、サーバーへアップしておきます。

 location ~ .*\.(jpg|jpeg|png|svg|webp|gif)$
 {
  error_page 400 403 404 /40x.png;
 }

その後設定ファイルを再度読み込みWebサーバを再起動します。

代替画像表示

画像が見つからないimg要素に代替画像を表示されました。

画像の読み込み状況をprogress要素(プログレスバー)で表示する

2023/12/29 (金) - 00:00 HTMLJavaScript

以下のように画像(img要素)がたくさんあるページで、画像の読み込み状況のパーセンテージをテキストとprogress要素で目視で確認できるようにしたい…。

プログレスバーのイメージ

HTMLで画像とprogress要素、読み込みのパーセンテージを表示するテキスト領域を用意します。

<p id="load">Loading:0%</p>
<progress value="0" max="100" id="progress"></progress>
<p><img src="sample1.jpg" width="640" height="480" alt="画像1"></p>
<p><img src="sample2.jpg" width="640" height="480" alt="画像2"></p>
<p><img src="sample3.jpg" width="640" height="480" alt="画像3"></p>

JavaScriptのコードです。img要素の数だけループを回して画像の読み込みが完了したら数値とプログレスバーに反映させます。また、万が一画像が見つからないなどエラーのときも無視して数値とプログレスバーに反映させて不整合が起きないようにしました。

window.addEventListener('DOMContentLoaded', function () {
 const loadElm = document.getElementById('load');
 const imgElm = document.querySelectorAll('img');
 const progressElm = document.getElementById('progress');
 const imgMax = imgElm.length;
 let count = 0;
 const loadResult = () => {
  return Math.floor(count / imgMax * 100);
 }
 imgElm.forEach((elm) => {
  elm.addEventListener('error', (e) => {
   count++;
   loadElm.textContent = `Loading:${loadResult()}%`;
   progressElm.value = loadResult();
   console.error(`Error: ${e.target.src}`); //エラーのあった画像ファイル名をコンソールに表示
  });
  elm.addEventListener('load', (e) => {
   count++;
   loadElm.textContent = `Loading:${loadResult()}%`;
   progressElm.value = loadResult();
   console.log(`Load: ${e.target.src}`); //読みんだ画像ファイル名をコンソールに表示
  });
 });
});

実行例。progress要素などの見た目はCSSでカスタマイズしています。

実際の動き

注意点としては、スクロールにそって画像を遅延読み込みさせるJavaScriptライブラリや、img要素のloading="lazy"属性は使用しないよう注意しましょう。事前に画像が読み込まれなくなってしまうので正常にローディングが動きません。

Next.js App Routerによるhead要素内の設定(meta OGPとかfavicon)

2023/12/27 (水) - 00:00 HTMLJavaScript

Next.js 13以降で採用されたApp Routerにて、head要素内にmetaタグを設定する場合のメモ。Metadata APIをつかえば、title(ページタイトル)やmeta description(サイト説明文)のほか、OGPや、favicon、カノニカルURLの設定も可能です。

export const metadata = {
 /*ページタイトルと説明*/
 title: 'たかしのホームページ',
 description: 'たかしのホームページです',
 /*電話番号の自動リンク無効化*/
 formatDetection: {
  telephone: false,
 },
 /*OGP*/
 openGraph: {
  title: 'たかしのホームページ',
  description: 'たかしのホームページです',
  url: 'https://example.com/',
  siteName: 'たかしのホームページ',
  images: [
   {
    url: 'https://example.com/img/opg.png',
    width: 1200,
    height: 630,
   }
  ],
  locale: 'ja_JP',
  type: 'website',
 },
 /*iOS ホームアイコン向け設定*/
 appleWebApp: {
  title: 'たかしHP'
 },
 /*faviconとtouch-icon*/
 icons: {
  icon: '/favicon.ico',
  shortcut: '/favicon.ico',
  apple: '/apple-icon.png',
  other: {
   rel: 'apple-touch-icon-precomposed',
   url: '/apple-icon.png',
  },
 },
 /*カノニカル*/
 alternates: {
  canonical: 'https://example.com/',
 },
}

出力されたコード(Next.jsが出力するコードやCSSなどは省略しています)

<head>
 <meta charset="utf-8"> ←自動出力
 <meta name="viewport" content="width=device-width, initial-scale=1"> ←自動出力
 <title>たかしのホームページ</title>
 <meta name="description" content="たかしのホームページです">
 <meta name="format-detection" content="telephone=no">
 <meta name="apple-mobile-web-app-capable" content="yes">
 <meta name="apple-mobile-web-app-title" content="たかしHP">
 <meta name="apple-mobile-web-app-status-bar-style" content="default">
 <meta property="og:locale" content="ja_JP">
 <meta property="og:title" content="たかしのホームページ">
 <meta property="og:description" content="たかしのホームページです">
 <meta property="og:url" content="https://example.com/">
 <meta property="og:site_name" content="たかしのホームページ">
 <meta property="og:image" content="https://example.com/img/opg.png">
 <meta property="og:image:width" content="1200">
 <meta property="og:image:height" content="630">
 <meta property="og:type" content="website">
 <meta name="twitter:card" content="summary_large_image">
 <meta name="twitter:title" content="たかしのホームページ">
 <meta name="twitter:description" content="たかしのホームページです">
 <meta name="twitter:image" content="https://example.com/img/opg.png">
 <meta name="twitter:image:width" content="1200">
 <meta name="twitter:image:height" content="630">
 <link rel="canonical" href="https://example.com/">
 <link rel="shortcut icon" href="/favicon.ico">
 <link rel="icon" href="/favicon.ico">
 <link rel="apple-touch-icon" href="/apple-icon.png">
 <link rel="apple-touch-icon-precomposed" href="/apple-icon.png">
</head>

titleやfaviconも反映されました。

meta設定後のブラウザ

変数を使う

もちろん、変数を定義して値を呼び出して処理することも可能です。例えば、任意の共通ディレクトリに設定ファイルを置き共通のWebサイト名や説明文などを設定しておき、他のページから呼び出して使うなども可能です。例:setting.jsに共通の指定値を設定。

export const siteSeting = {
 sitename: 'たかしのホームページ', //サイト名
 url: 'https://example.com' //サイトのURL
}

各下層ページのlayout.jsにてimport。(注意:CSSやヘッダーコンポーネントなどの記述は省略しています)

import {siteSeting} from '../components/setting' //設定ファイルimport
const pageTitle = '自己紹介'; //ページタイトル
const pageUrl = 'profile'; //パス名
const pageDescription = 'たかしの自己紹介です'; //ページ説明文
export const metadata = {
 title: `${pageTitle} - ${siteSeting.sitename}`,
 description: `${pageDescription}`,
 openGraph: {
  title: `${pageTitle} - ${siteSeting.sitename}`,
  url: `${siteSeting.url}/${pageUrl}`,
  description: `${pageDescription}`,
 },
 alternates: {
  canonical: `${siteSeting.url}/${pageUrl}`
 }
}
export default function RootLayout({ children }) {
 return (
  <html lang="ja">
   <body>
    <main>
     <header>
      <h1>{pageTitle}</h1>
      <h2>{pageDescription}</h2>
     </header>
     {children}
    </main>
   </body>
  </html>
 )
}

ページタイトルとディスクリプションを個別に設定

ページタイトルやURLが一気に変わりました。なお、Metadata APIに関する公式ドキュメントはこちらになります。

sessionStorageやlocalStorageではBoolean使えないのね…

2023/12/26 (火) - 00:00 JavaScript

sessionStoragelocalStorageを使ったときにアレ?と思ったポイント。

sessionStorage.setItem('flg',true);
//あるいは
sessionStorage.setItem('flg',false);

//取得すると…
sessionStorage.getItem('flg'); //false
// →falseでもtrueに!?

trueでもfalseでもなぜかtrue判定されるようで。どうやらsessionStoragelocalStorageではBoolean型が格納できず、String型になるというのが13年くらい前の文献に書いてありました。

仕方ないのでtrueかfalseではなく、1か0にしました。

sessionStorage.setItem('flg',1);
//あるいは
sessionStorage.setItem('flg',0);

//取得する
let flg = parseInt(sessionStorage.getItem('flg'),10);
if( flg ){
// 1→true
}else{
// 0→false 
}

ただ、値が0以外の数値だとなんでもtrueになります。にゃるぴの脳はIE5くらいで止まっています…。

[ネタ]del要素を選択不可の黒塗り文字に、abbr属性のtitle 属性を表示させる…ほか

2023/12/22 (金) - 00:00 CSSHTML

CSSのテキスト装飾ネタ(使用の推奨はしません)

 黒塗りの書類

del要素を黒塗りにする

テキストを黒く塗りつぶして見えなくする実装です。ついでにテキスト選択も出来ないように。

CSSのコード

del{
 display: inline;
 background: #000;
 text-decoration:overline;
 color: #000;
 user-select: none;
}

なお、HTMLソース見たら内容がすぐわかるので意味はありません。またユーザの印象悪くなるのでネタとしてどうぞ。悪用厳禁です。

abbr要素のtitle属性を可視化

abbr要素は略語や単語の頭文字を包括する要素です。また必須ではありませんが、本来の単語とtitle属性で指定します。パソコンであれば単語の上にマウスオーバーすればtitle属性に指定した内容がツールチップ時で表示されますが、スマホやタブレットなどのタッチデバイスでは見えません。そこでCSSで可視化します。

HTMLのコード

<p><abbr title="HyperText Markup Language">HTML</abbr>とは、<abbr title="World Wide Web Consortium">W3C</abbr>が策定するマークアップ言語です。</p>

CSSのコード

abbr{
 text-decoration: none;
}
abbr::after{
 content: "("attr(title)")";
 color: #999;
 font-size: 88%;
}

擬似要素で見た目上で生成させるため、テキスト選択をしたりできず、音声ブラウザや非視覚系ブラウザでも無視されますので注意が必要です。

その他

Web1.0時代やガラケー(旧型モバイル)Webサイトでよく見かけたマーキーと点滅文字をCSSで再現しました。

他、おまけ(?)あり。Sorry, this site is Japanese only!

Next.jsのApp Routerでクエリパラメータ(GETパラメータ)と動的パラメータ(パス)の取得

2023/12/19 (火) - 00:00 JavaScriptPHP&CMS

Next.jsでは従来Page Routerをベースとしていましたが、Next.js 13以降ではApp Routerが採用されそれに伴いApp Routerを使用して開発することが推奨されています。…ので私もそれに習って勉強し直しです。

主にソースを配置するディレクトリ、ルーティングの設計が変わりました。今回はApp Routerにおけるクエリパラメータ(GETパラメータ)の取得と、動的パラメータ(Dynamic Params)の取得をテストしてみました。

環境は以下の通り。

  • Next.js 14.0.x
  • React.js 18.0.x

クエリパラメータの取得

任意の場所にpage.jsを作成し、以下のように記入しました。post_idというクエリパラメータを取得するとします。取得する際はuseSearchParamsを使用します。

"use client"; 
import { useSearchParams } from "next/navigation";
export default function Page() {
 const params = useSearchParams();
 const id = params.get('post_id');
 return (
  <main>
   <p>GETパラメータ post_idは、<i>{id}</i>です。</p>
  </main>
 );
}

アクセス結果

表示結果

動的パラメータの取得

従来のPage Routerで動的パラメータを使用する際には、任意のディレクトリに/pages/hoge/[id].jsのようなファイルを生成していましたが、App Routerでは/src/hoge/[id]/page.jsのような作成ルールに変わったようです。

そこで今回は[post_id]/page.jsを作成しました。取得する際はuseParamsを使用します。

"use client";
import { useParams } from "next/navigation";
export default function Page() {
 const prams = useParams();
 const post_id = prams.post_id;
 return (
  <main>
   <p>パスは、<i>{post_id}</i>です。</p>
  </main>
 );
}

表示結果

応用:取得したパラメータに応じてデータ表示

Next.jsで取得したパラメータに応じて表示を変えたい。今回は例として動的のAPIでid=10を読み込むと、以下のJSONが返ってくるものとします。

{
 "Member": [
  {
   "id": 10,
   "name": "櫻井優衣💖",
   "birthday":"2000.2.21",
   "place":"東京都",
   "content": "ねぇ 呼び出しなんてなぁになぁに?🥺"
  }
 ] 
}

クエリパラメータ・useSearchParamsを使った場合

useSearchParamsを使ったテストのコード。

"use client";
import { useSearchParams } from "next/navigation";
import { useState } from "react";
export default function Page() {
 const params = useSearchParams();
 const post_id = params.get('post_id');
 const [dataJSON, setdataJSON] = useState(null);
 const [loadJSON, setloadJSON] = useState(false);
 fetch(`https://example.com/member/?id=${post_id}`).then((res) => res.json()).then((data) => {
  setdataJSON(data)
  setloadJSON(true)
 })
 if(loadJSON){
  return (
   <main>
    <p>GETパラメータ post_idは、<i>{post_id}</i>です。</p>
    <hr />
    <h1>{dataJSON.Member[0].name}</h1>
    <p className="birthday">誕生日:{dataJSON.Member[0].birthday}</p>
    <p className="place">出身地:{dataJSON.Member[0].place}</p>
    <p className="content">{dataJSON.Member[0].content}</p>
   </main>
  );
 }else{
  return (
   <p>読み込み</p>
  );
 }
}

/member/post_id=10のアクセス結果。

動的JSON取得した表示結果

動的パラメータ・useParamsを使った場合

useParamsを使った場合を使ったテストのコード。

"use client";
import { useParams } from "next/navigation";
import { useState } from "react";
export default function Page() {
 const prams = useParams();
 const post_id = prams.post_id;
 const [dataJSON, setdataJSON] = useState(null);
 const [loadJSON, setloadJSON] = useState(false);
 fetch(`https://example.com/member/?id=${post_id}`).then((res) => res.json()).then((data) => {
  setdataJSON(data)
  setloadJSON(true)
 })
 if(loadJSON){
  return (
   <main>
    <p>パスは、<i>{post_id}</i>です。</p>
    <hr />
    <h1>{dataJSON.Member[0].name}</h1>
    <p className="birthday">誕生日:{dataJSON.Member[0].birthday}</p>
    <p className="place">出身地:{dataJSON.Member[0].place}</p>
    <p className="content">{dataJSON.Member[0].content}</p>
   </main>
  );
 }else{
  return (
   <p>読み込み</p>
  );
 }
}

/member/10/のアクセス結果。

動的JSON取得した表示結果

今回はNext.jsのApp Routerを試しました。上記のコードはクライアントコンポーネントで使えるものなので、サーバーサイドでできるようにするには少し変える必要があります。また別の機会に試したいと思います。

ReactをCDNで読み込み、外部JSONファイルをAjaxで取得してみた

2023/12/15 (金) - 00:00 JavaScript

ReactのJSファイルをCDNを使って読み込み、さらにReactを使って外部のJSONAjaxで取得し、ブラウザ画面に表示させるJavaScriptのサンプルを作成しました。

サンプルのコード

JavaScriptの準備。CDNを使ってReact本体を呼び出します。

<script src="https://unpkg.com/react@16.14.0/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16.14.0/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/babel-standalone@6.26.0/babel.min.js"></script>

コンテナの準備。HTMLの任意の場所にReactを描写させるDOM要素を準備しておきます。

<div id="app"></div>

今回使うJSONファイルです。例としてnonameweaponの値を持っているものとします。

{
"Party": [
  { "no": 1,"name": "マリオ", "weapon": "ひまんパタこうら" },
  { "no": 2,"name": "マロ", "weapon": "ソニックシンバル" },
  { "no": 3,"name": "ジーノ", "weapon": "スターガン" },
  { "no": 4,"name": "クッパ", "weapon": "ドリルクロー" },
  { "no": 5,"name": "ピーチ姫", "weapon": "フライパン" }
 ] 
}

以下は実行コードになります。PARTYというReactコンポーネントを作成し、ajaxで外部のJSONファイルにアクセス。名前(name)と武器名(weapon)を取得してJSXでブラウザ画面上に描写させます。

class PARTY extends React.Component {
 constructor(props) {
  super(props);
  this.state ={
   status: null,
   party: []
  }
 }
 componentDidMount(){
  //JSONのファイル名
  fetch("party.json")
  .then(res => res.json())
  .then(
    (data) => {
     this.setState({
     status: 'success',
     party: data.Party
    });
   },
   (error) => {
    this.setState({
     status: 'error'
    });
   }
  )
 }
 render() {
  if (this.state.status === 'success') {
   let partys = this.state.party.map((party) => { return <li key={party.no}>名前:{party.name} 武器:{party.weapon}</li>});
   return <ul>{partys}</ul>
  }else if(this.state.status === 'error') {
   return <p>エラーです</p>
  }else{
   return <p>読み込み中</p>
  }
 }
}
ReactDOM.render(<PARTY />,document.getElementById('app'));

JSXとは、Reactでよく使われる仕組みでJavaScriptのコードの中にXMLのようなマークアップのコードを記述するものです。

実行結果

名前と武器がリストで表示されます。

<ul>
<li>名前:マリオ 武器:ひまんパタこうら</li>
<li>名前:マロ 武器:ソニックシンバル</li>
<li>名前:ジーノ 武器:スターガン</li>
<li>名前:クッパ 武器:ドリルクロー</li>
<li>名前:ピーチ姫 武器:フライパン</li>
</ul>

「フィクションです。じっさいの人物には、いっさい関係ありません。」以上。

img要素のwidth/height属性を省いてはいけない(戒め)

2023/12/12 (火) - 00:00 DesignHTML

古くから画像のimgタグに対して必ず横幅(width)と高さ(height)を指定しないといけない…といわれていました。しかしCSSレイアウトとレスポンシブWebデザインやリキッドレイアウトが主流になってからは、HTML側のimg要素のwidthheight属性指定を省いて、CSSでimgに対して横幅だけ指定して、高さはフレキシブルに伸縮させる事が多くなりました(個人の感覚)。

誤ってエ□広告タップしてしまった!

<img src="sample.webp" alt="我が家の猫ですにゃ" loading="lazy" />

CSSの記述

img{
 width: 100%;
 height: auto;
}

しかし、現在においてもHTMLでimgに対しwidth/height属性をしっかりと指定することが推奨されています。その理由は下記のとおり。

  • レンダリングのスピードが上がる
  • レイアウト崩れを防ぐことができる(レイアウトシフトの防止)
  • 遅延読み込み(loading="lazy")にも適切

レイアウトシフトの防止

HTMLのimg要素に予めwidthやheightを指定しておくと、レイアウトシフトを防ぐことが出来ます。

レイアウトシフトの発生例

レイアウトシフトとは、Webページにアクセスした際にバナー画像や本文中の画像が後から遅れて読み込まれることで発生する、レイアウト崩れやスクロール位置がズレる現象のことです。これにより文字を読んでいる途中に急に画像が表示され今自分がどこを読んでいたのかを見失ってしまったりします。

ほかにも本文中のボタンやリンクをクリック(タップ)しようとした瞬間、急にバナー画像が表示され本文がズレてしまい関係ない広告に意図せずアクセスしてしまう…ということも考えられます。閲覧しているユーザーにとってこれほどまでにストレスになる事はありません。

レイアウトシフト防止例

原因はブラウザ側では画像の読み込みが完了するまで画像の大きさを把握できないため、高さが0の状態になり画像が読み込まれた瞬間に高さが急に確保されるために起こります。しかしHTMLのimg要素に予めwidthやheightを指定しておけば画像が読み込まれている最中も画像分の高さをある程度確保した状態でレンダリングされるため、レイアウトシフトを防止しユーザーのストレスも軽減できます。

特にimg要素に対し、loading="lazy"の属性で遅延読み込みを指せる際は大幅なズレや解消できます。そのうえでCSSで適切なサイズに調整しましょう。

パソコンとスマホ レスポンシブで画像を切り替える場合

パソコンとスマートフォンで画像とサイズを切り替えたい場合があると思います。PCでは横長画像、スマホでは縦長など。そういう場合はpicture要素とsource要素を使ってPCとスマホのそれぞれの画像ファイルとサイズを指定します。

PCとスマホで画像分ける例

以下のようなコードになります。

<picture>
 <source media="(max-width:639px)" srcset="SP.webp" width="640" height="960"><!--スマホ用画像とサイズ-->
 <img src="PC.webp" alt="クリスマスセール" width="1600" height="900" loading="lazy"><!--パソコン用画像とサイズ-->
</picture>

例ではsource要素にメディアクエリとブレークポイント、さらにスマホ用画像とサイズを指定し、img要素にPC用の画像ファイルとサイズを指定しています。

古のルールはちゃんと理由があるってことですね。以上自分自身の戒めのためのメモでした。

Next.js13のApp Roterで404ページ作成&静的エクスポート

2023/12/09 (土) - 00:00 JavaScript

404 Not Foundページの作成

Next.js 13以降で採用されたApp RoterでWebページ作成中。404 Not Foundページの作成方法が、Page Routerの時と変わっていたのでもメモ。公式ドキュメントに書いてありました。

App Roterでは、appディレクトリにnot-found.jsのファイルを生成するようです。

import Link from "next/link";
export const metadata = {
 title: 'ページが見つかりません'
}
export default function Error404() {
 return (
  <div>
   <h1>ファイルがない…ただの屍のようだ…</h1>
   <Link href="/">TOP PAGE</Link>
  </div>
 )
}

表示イメージ(ヘッダーやグローバルナビは無視して下さい)

404エラーページのサンプル

静的エクスポート Static Exports(Static HTML Export)

ついでに、Next.js 13.4ではNext.jsで構築したアプリケーションを静的ファイルに書き出す静的エクスポート<Static Exports(Static HTML Export)>のコマンドである、next exportが廃止されやり方が変わっていたのでそれもメモ。

next.config.jsでコンフィグの中に、output: 'export'を記述。

/** @type {import('next').NextConfig} */
const nextConfig = {
 output: 'export',
}
module.exports = nextConfig

エクスポートを実行。

% npm run build

ビルドが実行されるのでしばらく待ちます。何事もエラーがなければ終了します。ファイルは/out/のディレクトリに生成されます。

下層ページをディレクトリごと出力する

このままエクスポートすると、たとえばabout/page.jsは、about.htmlとして静的ファイルが出力されます。

exportの設定前

これをabout/という風にディレクトリごとに出力したい場合は、コンフィグファイルに設定を加えます。先ほどのnext.config.jsの設定値の行の次に、trailingSlash: trueを追加し、再度エクスポートをします。

/** @type {import('next').NextConfig} */
const nextConfig = {
 output: 'export',
 trailingSlash: true
}
module.exports = nextConfig

すると、about/index.htmlのように出力追加されます。

exportの設定後

ブラウザでもabout.htmではなく、about/でアクセスできるようになりました。

さくらのレンタルサーバーでMovable Type(MT)の管理画面がForbiddenになる件

2023/12/08 (金) - 00:00 PHP&CMSServer

さくらのレンタルサーバーでMovable Type 7(MT7)を使い、管理画面でデザインテンプレートを更新しようとしたところ、画面が白くなりForbiddenというエラーに…。ブラウザのキャッシュやCookieを削除して再度実行しても改善せず。そういえばロリポップでも同様なことがあったな…?と、ある改善を試したら直りました。

その犯人とは…WAF(Web Application Firewall)です。

WAFとはWebアプリケーションを不正な攻撃から守る機能の1つで、さくらのレンタルサーバーでも標準で搭載されています。SQLインジェクションやXSSなど、Webアプリケーションの脆弱性から守ってくれます。今回、MT管理画面の入力フォームに記述したMTタグやHTMLタグの記述がXSSと誤認識されアクセスを遮断したものと考えられます。

一時的にWAFを無効にする

さくらのレンタルサーバーコントロールパネルのWAF設定

さくらのレンタルサーバーのコントロールパネルにログイン後、[セキュリティ]→[WAF設定ドメイン]と選択します。対象のドメインの欄の[設定]を選択し[WAF設定変更]から[利用しない]にチェックを入れ[保存する]を押下します。

しばらくしたら、MTの管理画面から正常にデザインテンプレートが更新でき再構築できるか試したら正常に動きました。

Movable Typeで保存ができました

再びにWAFを有効にする

安全のためWAF設定をもとに戻しておきます。先程の設定で今度は逆に[利用する]を選択し保存します。

さくらのレンタルサーバーのWAFの有無をディレクトリやファイルごとで設定できないようなので、面倒ではありますが随時切り替えて運用することにします。

ページの先頭へ