Create a gist now

Instantly share code, notes, and snippets.

@Aquei /Sri.php
Last active Sep 23, 2017

What would you like to do?
wordpress plugin for jsdelivr
<?php
/*
Plugin Name: jsdelivred
Plugin URI: https://gist.github.com/Aquei/7dd4c9a7d1f4b9bd48f3d6ba9a036daa
Description: Load default WordPress assets from jsdelivr
Version: 1.0.1
Author: Aquei
Author URI: https://blog.srytk.com/aquei/
License: Apache 2.0
*/
namespace jsdelivred;
require_once(__DIR__ . "/Sri.php");
function get_file($src){
if(0 !== strpos($src, "http")){
$path = dirname(WP_CONTENT_DIR) . "/${src}";
return file_get_contents($path);
}else{
return False;
}
}
function filter_url($src, $handle, &$dep){
global $wp_version;
//登録されないファイルのハンドル
$manual_handle = ["concatemoji"];
//cdnのルートパス
$base = "https://cdn.jsdelivr.net/gh/WordPress/WordPress@${wp_version}";
if(
0 === strpos($src, $dep->base_url)
&& False === strpos($src, ".php")
&& $dep->query($handle)
){
$asset = $dep->registered[$handle];
$relative = $asset->src;
$data = get_file($relative); //存在チェック
if($data !== False && $relative){
//デフォルトディレクトリに存在するかチェックして、なかったらそのまま返す
if(!$dep->in_default_dir($relative)){
return $src;
}
$sri = new Sri($data);
/* Subresource Integrityを追加 */
$integrity = $sri->get_integrity("sha384", False);
$dep->add_data($handle, "data_sri", $integrity);
return $base . $relative;
}else{
return $src;
}
}elseif(in_array($handle, $manual_handle, True)){
//登録されないファイルの処理
$site_url = site_url();
if(0 === strpos($src, $site_url)){
$cdn_url = remove_query_arg("ver", str_replace($site_url, $base, $src));
return $cdn_url;
}else{
return $src;
}
}else{
return $src;
}
}
function filter_script_url($src, $handle){
global $wp_scripts;
return filter_url($src, $handle, $wp_scripts);
}
add_filter("script_loader_src", "jsdelivred\\filter_script_url", 10, 2);
function filter_style_url($src, $handle){
global $wp_styles;
return filter_url($src, $handle, $wp_styles);
}
add_filter("style_loader_src", "jsdelivred\\filter_style_url", 10, 2);
function add_integrity_attr($tag, $handle, $tag_name, &$dep){
if(strpos($tag, "integrity") === False && $sri = $dep->get_data($handle, "data_sri")){
if(substr_count($tag, "<${tag_name}") > 1){
//script with inlines
$ptn = '@<script\b([^>]*)\bsrc=@i';
return preg_replace($ptn, "<script integrity=\"${sri}\" crossorigin \\1 src=", $tag);
}else{
//single script tag or stylesheet
return str_replace("<${tag_name}", "<${tag_name} integrity=\"${sri}\" crossorigin", $tag);
}
}else{
return $tag;
}
}
function filter_script_sri_attr($tag, $handle){
global $wp_scripts;
return add_integrity_attr($tag, $handle, "script", $wp_scripts);
}
add_filter("script_loader_tag", "jsdelivred\\filter_script_sri_attr", 10, 2);
function filter_style_sri_attr($tag, $handle){
global $wp_styles;
return add_integrity_attr($tag, $handle, "link", $wp_styles);
}
\add_filter("style_loader_tag", "jsdelivred\\filter_style_sri_attr", 10, 2);
<?php
namespace jsdelivred;
/**
Subresource Integrityを求めるクラス
*/
class Sri
{
/* ハッシュを計算する元のデータ */
protected $data;
/** @param string $data sriを計算するデータ */
function __construct($data){
$this->data = $data;
}
/**
* @access public
* @param array ハッシュアルゴリズムの配列
* @param boolean (optional) 対応してないハッシュアルゴリズムが指定されていた時例外を出さないようにする
* @return string sri値
*/
public function get_integrity($algos, $ignore=True){
$sris = [];
$supported = hash_algos();
foreach((array) $algos as $algo){
$algo = strtolower($algo);
if(array_search($algo, $supported) === False){
if(!$ignore){
throw Exception("サポートされていないハッシュアルゴリズム: $algo");
}else{
continue;
}
}
$hash = hash($algo, $this->data, True);
$encoded = base64_encode($hash);
array_push($sris, "${algo}-${encoded}");
}
return implode(" ", $sris);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment