tips

WPの外部画像URLをSSL対応

SSL対応時にどうしても混在コンテンツを回避できない場合に

WP+SSL化で検索すると、自作ブログのSSL化ばかりが話題になりますが、
実際のクライアントワークでは、SSL対応時にどうしても混在コンテンツを回避できないケースがままあります。
SSLやめるのは本末転倒ですし、外部画像のURLを変えてもらうように言えず、コピペしがちなケースが多い現場に細かい注意点を引き継いでいただくのは至難の技です。

そこで、外部画像URLをphpで擬似イメージプロキシして、ちょっと強引に表示を実現します。
例えば、googleのロゴを非SSLで読み込むと以下のようなURLになります。

WPの外部画像URLをSSL対応
<img src="http://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png" />

これをフィルターを通すと、こう加工されて出力されます。

<img src="https://web.contempo.jp/imageproxy?src=www.google.com%2Fimages%2Fbranding%2Fgooglelogo%2F2x%2Fgooglelogo_color_272x92dp.png" />

専用のphpを用意するとか嫌なんで、wpフックでimageproxyというurlを読み込んだ場合にphpで画像を取得して吐き出すようにしています。処理的にどうかと思う部分がないでもないですが、個人的には保守性の高さの方が重要だと思う。 第三者に利用されないように HTTP_REFERER で判定を入れています。

フック先は画像を貼り付けてそうなメインエディタ、コメント、ウィジェットの三つのテキストに引っ掛けてあります。

if ( $_SERVER['HTTPS'] == 'on' ){

add_filter( 'the_content', 'change_image_src_for_proxy', 99 );
add_filter( 'comment_text', 'change_image_src_for_proxy', 99 );
add_filter( 'widget_text', 'change_image_src_for_proxy', 99 );

function change_image_src_for_proxy( $content ){
    preg_match_all('/<img[^>]*src=[\'"]http:\/\/(.*?)[\'"][^>]*>/i', $content, $matches, PREG_SET_ORDER);
    foreach ($matches as $match):
        $homeurl = str_replace( 'https://', '', home_url() );
        if ( stripos( $match[2], $homeurl ) === 0 ){
            $img = str_replace( 'http://', 'https://', $match[0] );
        } else {
            $img = str_replace( 'http://'.$match[1], add_query_arg( 'src' => $match[1], home_url('imageproxy') ), $match[0] );
        }
        $content = str_replace( $match[0], $img, $content );
    endforeach;
    return $content;
}


add_action( 'send_headers', function() {
    global $wp;
    if ( $wp->request !== 'imageproxy' || empty( $_GET['src'] ) ) return;
    if ( strpos( ( $_SERVER['HTTP_REFERER'] ?? '' ), home_url() ) !== 0 ) return;
    $src = $_GET['src'];
    if ( stripos( $src, 'http://' ) !== 0 ) return;
    if ( !parse_url( $src, PHP_URL_HOST ) ) return;
    $response = wp_safe_remote_get( $src, [ 'timeout' => 10 ] );
    if ( is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) !== 200 ) return;
    $content_type = strtolower( explode( ';', wp_remote_retrieve_header( $response, 'content-type' ) )[0] );
    if ( strpos( $content_type, 'image/' ) !== 0 ) return;
    header( 'Content-Type: ' . $content_type );
    echo wp_remote_retrieve_body( $response );
    exit;
}, -1 );

}

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です