编辑
设置图片

php
POST /wp-admin/admin-ajax.php HTTP/1.1
Host: wp
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:152.0) Gecko/20100101 Firefox/152.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.9,zh-TW;q=0.8,zh-HK;q=0.7,en-US;q=0.6,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 77
Origin: http://wp
Connection: keep-alive
Referer: http://wp/wp-admin/post-new.php
Cookie: wordpress_3b7f056b9775e5cd94a7cc21da1e2639=admin%7C1784729158%7Co4s2XNop0AdtgOa1jVMrb2P8MkQ4YZrIUcEyGGlJLdu%7C5f3f858286de7410e0ce3272b0c9e9ffa6c3ea76e9a5bdd36fb9069ded0733eb; wp-saving-post=1-check; wordpress_logged_in_3b7f056b9775e5cd94a7cc21da1e2639=admin%7C1784729158%7Co4s2XNop0AdtgOa1jVMrb2P8MkQ4YZrIUcEyGGlJLdu%7Cfd92c6cc37837f548361f25994268c449baf369a95603b04b1c0d5c9297888af; wp-settings-time-1=1783690363; wp-settings-1=libraryContent%3Dbrowse%26align%3Dleft
Priority: u=0
post_id=17&thumbnail_id=15&_wpnonce=3a6f29f4bf&action=get-post-thumbnail-html
php
function wp_ajax_get_post_thumbnail_html() {
//postid
$post_ID = intval( $_POST['post_id'] );
//post_id=17
check_ajax_referer( "update-post_$post_ID" );
if ( ! current_user_can( 'edit_post', $post_ID ) ) {
wp_die( -1 );
}
$thumbnail_id = intval( $_POST['thumbnail_id'] );
// For backward compatibility, -1 refers to no featured image.
if ( -1 === $thumbnail_id ) {
$thumbnail_id = null;
}
$return = _wp_post_thumbnail_html( $thumbnail_id, $post_ID );
wp_send_json_success( $return );
}
php
function check_ajax_referer( $action = -1, $query_arg = false, $die = true ) {
//update-post_17
if ( -1 == $action ) {
_doing_it_wrong( __FUNCTION__, __( 'You should specify a nonce action to be verified by using the first parameter.' ), '4.7' );
}
$nonce = '';
//$_REQUEST[$query_arg] 用于动态获取 HTTP 请求中的参数值,其具体来源取决于请求方式(GET、POST 或 COOKIE)。
if ( $query_arg && isset( $_REQUEST[ $query_arg ] ) )
$nonce = $_REQUEST[ $query_arg ];
elseif ( isset( $_REQUEST['_ajax_nonce'] ) )
$nonce = $_REQUEST['_ajax_nonce'];
//3a6f29f4bf
elseif ( isset( $_REQUEST['_wpnonce'] ) )
$nonce = $_REQUEST['_wpnonce'];
//这里3a6f29f4bf,update-post_17
$result = wp_verify_nonce( $nonce, $action );
/**
* Fires once the Ajax request has been validated or not.
*
* @since 2.1.0
*
* @param string $action The Ajax nonce action.
* @param false|int $result False if the nonce is invalid, 1 if the nonce is valid and generated between
* 0-12 hours ago, 2 if the nonce is valid and generated between 12-24 hours ago.
*/
//递归
do_action( 'check_ajax_referer', $action, $result );
if ( $die && false === $result ) {
if ( wp_doing_ajax() ) {
wp_die( -1, 403 );
} else {
die( '-1' );
}
}
return $result;
}
php
function wp_verify_nonce( $nonce, $action = -1 ) {
//这里3a6f29f4bf,update-post_17
$nonce = (string) $nonce;
$user = wp_get_current_user();
$uid = (int) $user->ID;
if ( ! $uid ) {
$uid = apply_filters( 'nonce_user_logged_out', $uid, $action );
}
if ( empty( $nonce ) ) {
return false;
}
$token = wp_get_session_token();
$i = wp_nonce_tick();
//这里计算
$expected = substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce'), -12, 10 );
//对比
if ( hash_equals( $expected, $nonce ) ) {
return 1;
}
//对比
$expected = substr( wp_hash( ( $i - 1 ) . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );
if ( hash_equals( $expected, $nonce ) ) {
return 2;
}
do_action( 'wp_verify_nonce_failed', $nonce, $action, $user, $token );
//
return false;
}
endif;
//function_exists 是 PHP 语言的内置函数,用于检测指定函数是否已定义。
if ( !function_exists('wp_create_nonce') ) :
php
function apply_filters( $tag, $value ) {
global $wp_filter, $wp_current_filter;
$args = array();
// Do 'all' actions first.
if ( isset($wp_filter['all']) ) {
$wp_current_filter[] = $tag;
$args = func_get_args();
_wp_call_all_hook($args);
}
if ( !isset($wp_filter[$tag]) ) {
if ( isset($wp_filter['all']) )
array_pop($wp_current_filter);
return $value;
}
if ( !isset($wp_filter['all']) )
$wp_current_filter[] = $tag;
if ( empty($args) )
$args = func_get_args();
array_shift( $args );
//这里调用
$filtered = $wp_filter[ $tag ]->apply_filters( $value, $args );
array_pop( $wp_current_filter );
return $filtered;
}
php
function do_action($tag, $arg = '') {
global $wp_filter, $wp_actions, $wp_current_filter;
if ( ! isset($wp_actions[$tag]) )
$wp_actions[$tag] = 1;
else
++$wp_actions[$tag];
if ( isset($wp_filter['all']) ) {
$wp_current_filter[] = $tag;
$all_args = func_get_args();
_wp_call_all_hook($all_args);
}
if ( !isset($wp_filter[$tag]) ) {
if ( isset($wp_filter['all']) )
array_pop($wp_current_filter);
return;
}
if ( !isset($wp_filter['all']) )
$wp_current_filter[] = $tag;
$args = array();
//
if ( is_array($arg) && 1 == count($arg) && isset($arg[0]) && is_object($arg[0]) ) // array(&$this)
$args[] =& $arg[0];
else
$args[] = $arg;
for ( $a = 2, $num = func_num_args(); $a < $num; $a++ )
//处理2
$args[] = func_get_arg($a);
//这里
$wp_filter[ $tag ]->do_action( $args );
array_pop($wp_current_filter);
}
php
public function do_action( $args ) {
$this->doing_action = true;
$this->apply_filters( '', $args );
// If there are recursive calls to the current action, we haven't finished it until we get to the last one.
if ( ! $this->nesting_level ) {
$this->doing_action = false;
}
}
php
<?php
/**
* WordPress Ajax Process Execution
*
* @package WordPress
* @subpackage Administration
*
* @link https://codex.wordpress.org/AJAX_in_Plugins
*/
//标识 AJAX 环境:将 DOING_AJAX 常量设置为 true,告知 WordPress 内核及插件当前正在处理异步请求,从而跳过常规的页面加载流程(如主题模板渲染),直接执行特定逻辑 。
//定义常量
define( 'DOING_AJAX', true );
//如果没有定义WP_ADMIN
if ( ! defined( 'WP_ADMIN' ) ) {
//定义
define( 'WP_ADMIN', true );
}
/** Load WordPress Bootstrap */
//固定位置
require_once( dirname( dirname( __FILE__ ) ) . '/wp-load.php' );
//发送来源标头
//允许跨域请求(从前端)。
//校验
send_origin_headers();
//检查参数
if ( empty( $_REQUEST['action'] ) )
die( '0' );
//包含
require_once( ABSPATH . 'wp-admin/includes/admin.php' );
require_once( ABSPATH . 'wp-admin/includes/ajax-actions.php' );
//请求头
@header( 'Content-Type: text/html; charset=' . get_option( 'blog_charset' ) );
@header( 'X-Robots-Tag: noindex' );
//校验
send_nosniff_header();
//缓存校验
nocache_headers();
//$wp_actions[$tag] 记录这个事件被喊了多少次
//初始化
do_action( 'admin_init' );
//数组
$core_actions_get = array(
'fetch-list', 'ajax-tag-search', 'wp-compression-test', 'imgedit-preview', 'oembed-cache',
'autocomplete-user', 'dashboard-widgets', 'logged-in',
);
$core_actions_post = array(
'oembed-cache', 'image-editor', 'delete-comment', 'delete-tag', 'delete-link',
'delete-meta', 'delete-post', 'trash-post', 'untrash-post', 'delete-page', 'dim-comment',
'add-link-category', 'add-tag', 'get-tagcloud', 'get-comments', 'replyto-comment',
'edit-comment', 'add-menu-item', 'add-meta', 'add-user', 'closed-postboxes',
'hidden-columns', 'update-welcome-panel', 'menu-get-metabox', 'wp-link-ajax',
'menu-locations-save', 'menu-quick-search', 'meta-box-order', 'get-permalink',
'sample-permalink', 'inline-save', 'inline-save-tax', 'find_posts', 'widgets-order',
'save-widget', 'delete-inactive-widgets', 'set-post-thumbnail', 'date_format', 'time_format',
'wp-remove-post-lock', 'dismiss-wp-pointer', 'upload-attachment', 'get-attachment',
'query-attachments', 'save-attachment', 'save-attachment-compat', 'send-link-to-editor',
'send-attachment-to-editor', 'save-attachment-order', 'heartbeat', 'get-revision-diffs',
'save-user-color-scheme', 'update-widget', 'query-themes', 'parse-embed', 'set-attachment-thumbnail',
'parse-media-shortcode', 'destroy-sessions', 'install-plugin', 'update-plugin', 'press-this-save-post',
'press-this-add-category', 'crop-image', 'generate-password', 'save-wporg-username', 'delete-plugin',
'search-plugins', 'search-install-plugins', 'activate-plugin', 'update-theme', 'delete-theme',
'install-theme', 'get-post-thumbnail-html',
);
$core_actions_post[] = 'wp-fullscreen-save-post';
// 获取action,判断是否包含
if ( ! empty( $_GET['action'] ) && in_array( $_GET['action'], $core_actions_get ) )
//拼接
//str_replace 是 PHP 中用于字符串替换的内置函数
//1
//添加插件修改
add_action( 'wp_ajax_' . $_GET['action'], 'wp_ajax_' . str_replace( '-', '_', $_GET['action'] ), 1 );
//添加插件修改
if ( ! empty( $_POST['action'] ) && in_array( $_POST['action'], $core_actions_post ) )
add_action( 'wp_ajax_' . $_POST['action'], 'wp_ajax_' . str_replace( '-', '_', $_POST['action'] ), 1 );
//默认
//注册回调函数
add_action( 'wp_ajax_nopriv_heartbeat', 'wp_ajax_nopriv_heartbeat', 1 );
//获取登录用户信息
if ( is_user_logged_in() ) {
/**
* Fires authenticated Ajax actions for logged-in users.
*
* The dynamic portion of the hook name, `$_REQUEST['action']`,
* refers to the name of the Ajax action callback being fired.
*
* @since 2.1.0
*/
do_action( 'wp_ajax_' . $_REQUEST['action'] );
} else {
/**
* Fires non-authenticated Ajax actions for logged-out users.
*
* The dynamic portion of the hook name, `$_REQUEST['action']`,
* refers to the name of the Ajax action callback being fired.
*
* @since 2.8.0
*/
do_action( 'wp_ajax_nopriv_' . $_REQUEST['action'] );
}
// Default status
die( '0' );
php
function do_action($tag, $arg = '') {
global $wp_filter, $wp_actions, $wp_current_filter;
if ( ! isset($wp_actions[$tag]) )
$wp_actions[$tag] = 1;
else
++$wp_actions[$tag];
// Do 'all' actions first
if ( isset($wp_filter['all']) ) {
$wp_current_filter[] = $tag;
$all_args = func_get_args();
_wp_call_all_hook($all_args);
}
if ( !isset($wp_filter[$tag]) ) {
if ( isset($wp_filter['all']) )
array_pop($wp_current_filter);
return;
}
if ( !isset($wp_filter['all']) )
$wp_current_filter[] = $tag;
$args = array();
if ( is_array($arg) && 1 == count($arg) && isset($arg[0]) && is_object($arg[0]) ) // array(&$this)
$args[] =& $arg[0];
else
$args[] = $arg;
for ( $a = 2, $num = func_num_args(); $a < $num; $a++ )
$args[] = func_get_arg($a);
$wp_filter[ $tag ]->do_action( $args );
array_pop($wp_current_filter);
}
php
function add_action($tag, $function_to_add, $priority = 10, $accepted_args = 1) {
//拼接,替换拼接,10,1
return add_filter($tag, $function_to_add, $priority, $accepted_args);
}
php
function add_filter( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) {
global $wp_filter;
if ( ! isset( $wp_filter[ $tag ] ) ) {
$wp_filter[ $tag ] = new WP_Hook();
}
//add_filter 是 WordPress 核心函数,用于将自定义函数挂载到特定的过滤钩子(Filter Hook)上
//插件
$wp_filter[ $tag ]->add_filter( $tag, $function_to_add, $priority, $accepted_args );
return true;
}
php
function do_action($tag, $arg = '') {
global $wp_filter, $wp_actions, $wp_current_filter;
if ( ! isset($wp_actions[$tag]) )
$wp_actions[$tag] = 1;
else
++$wp_actions[$tag];
//特殊"万能监听器"优先('all'),如果存在监听所有事件的钩子 'all',先执行它(入栈记录,避免循环调用)。这相当于"不管喊什么,先让这哥们听见"。
if ( isset($wp_filter['all']) ) {
$wp_current_filter[] = $tag;
$all_args = func_get_args();
_wp_call_all_hook($all_args);
}
if ( !isset($wp_filter[$tag]) ) {
if ( isset($wp_filter['all']) )
array_pop($wp_current_filter);
return;
}
if ( !isset($wp_filter['all']) )
$wp_current_filter[] = $tag;
$args = array();
if ( is_array($arg) && 1 == count($arg) && isset($arg[0]) && is_object($arg[0]) ) // array(&$this)
$args[] =& $arg[0];
else
$args[] = $arg;
for ( $a = 2, $num = func_num_args(); $a < $num; $a++ )
$args[] = func_get_arg($a);
$wp_filter[ $tag ]->do_action( $args );
array_pop($wp_current_filter);
}
php
function send_nosniff_header() {
//X-Content-Type-Options: nosniff 是一个HTTP响应头,它的作用是防止浏览器对某些类型的文件进行 MIME 类型嗅探。当服务器返回了一个文件,但是并没有在响应头中明确指出这个文件的 MIME 类型时,浏览器会尝试根据文件的内容猜测其类型。这种行为称为 MIME 类型嗅探。
//不让浏览器制作聪明
@header( 'X-Content-Type-Options: nosniff' );
}
php
function nocache_headers() {
//检查插件
$headers = wp_get_nocache_headers();
//销毁指定变量或函数,销毁$headers['Last-Modified']
unset( $headers['Last-Modified'] );
// 在PHP 5.3及以上版本中,如果你想确保不会发送Last-Modified头部(header),你可以通过几种方式来实现这一点。
//function_exists 是 PHP 语言的内置函数,用于检测指定函数是否已定义。
if ( function_exists( 'header_remove' ) ) {
//header_remove 是 PHP 内置函数,用于删除此前通过 header() 设置的 HTTP 响应头
@header_remove( 'Last-Modified' );
} else {
// In PHP 5.2, send an empty Last-Modified header, but only as a
// last resort to override a header already sent. #WP23021
//遍历
foreach ( headers_list() as $header ) {
//是PHP编程语言的内置函数,用于查找子字符串在目标字符串中首次出现的位置,且不区分大小写
if ( 0 === stripos( $header, 'Last-Modified' ) ) {
//设置
$headers['Last-Modified'] = '';
break;
}
}
}
php
function wp_get_nocache_headers() {
$headers = array(
'Expires' => 'Wed, 11 Jan 1984 05:00:00 GMT',
'Cache-Control' => 'no-cache, must-revalidate, max-age=0',
);
//function_exists 是 PHP 语言的内置函数,用于检测指定函数是否已定义。
//如果有
if ( function_exists('apply_filters') ) {
//apply_filters 是 WordPress PHP 核心函数,用于调用注册在指定钩子上的所有过滤器回调函数,修改并返回数据值,是实现插件/主题数据扩展的核心机制
//允许插件修改这个地方功能的方法
//允许插件修改nocache_headers值
$headers = (array) apply_filters( 'nocache_headers', $headers );
}
//不然这样设置,修改
$headers['Last-Modified'] = false;
//返回
return $headers;
}
php
function apply_filters( $tag, $value ) {
global $wp_filter, $wp_current_filter;
$args = array();
//
if ( isset($wp_filter['all']) ) {
$wp_current_filter[] = $tag;
$args = func_get_args();
_wp_call_all_hook($args);
}
if ( !isset($wp_filter[$tag]) ) {
if ( isset($wp_filter['all']) )
array_pop($wp_current_filter);
return $value;
}
if ( !isset($wp_filter['all']) )
$wp_current_filter[] = $tag;
if ( empty($args) )
$args = func_get_args();
array_shift( $args );
$filtered = $wp_filter[ $tag ]->apply_filters( $value, $args );
array_pop( $wp_current_filter );
return $filtered;
}
php
function send_origin_headers() {
//获取HTTP 请求头 Origin 的服务器变量,表示发起请求的源(协议 + 域名 + 端口),主要用于跨域资源共享(CORS)校验。
$origin = get_http_origin();
//网络校验,过滤变量
if ( is_allowed_http_origin( $origin ) ) {
@header( 'Access-Control-Allow-Origin: ' . $origin );
@header( 'Access-Control-Allow-Credentials: true' );
if ( 'OPTIONS' === $_SERVER['REQUEST_METHOD'] )
exit;
return $origin;
}
//$_SERVER['REQUEST_METHOD'] 是 PHP 中的一个超全局变量,用于获取当前 HTTP 请求的方法类型。
if ( 'OPTIONS' === $_SERVER['REQUEST_METHOD'] ) {
//跳转
status_header( 403 );
exit;
}
return false;
}
php
function is_allowed_http_origin( $origin = null ) {
$origin_arg = $origin;
if ( null === $origin )
$origin = get_http_origin();
//过滤白名单
if ( $origin && ! in_array( $origin, get_allowed_http_origins() ) )
$origin = '';
return apply_filters( 'allowed_http_origin', $origin, $origin_arg );
}
php
function get_http_origin() {
$origin = '';
//可以控制?
if ( ! empty ( $_SERVER[ 'HTTP_ORIGIN' ] ) )
//$_SERVER['HTTP_ORIGIN'] 是 PHP 中用于获取HTTP 请求头 Origin 的服务器变量,表示发起请求的源(协议 + 域名 + 端口),主要用于跨域资源共享(CORS)校验。
$origin = $_SERVER[ 'HTTP_ORIGIN' ];
//允许插件修改
return apply_filters( 'http_origin', $origin );
}
php
function do_action($tag, $arg = '') {
global $wp_filter, $wp_actions, $wp_current_filter;
//如果是空,没注册
if ( ! isset($wp_actions[$tag]) )
//1
$wp_actions[$tag] = 1;
else
//记录
++$wp_actions[$tag];
//有all
if ( isset($wp_filter['all']) ) {
//存储
$wp_current_filter[] = $tag;
//func_get_args() 是 PHP 中用来在函数内部获取所有传入参数的内置函数
$all_args = func_get_args();
_wp_call_all_hook($all_args);
}
//是空,不存在
if ( !isset($wp_filter[$tag]) ) {
//存在all
if ( isset($wp_filter['all']) )
//array_pop 是 PHP 编程语言中用来移除并返回数组最后一个元素的函数
array_pop($wp_current_filter);
return;
}
//空
if ( !isset($wp_filter['all']) )
//存储
$wp_current_filter[] = $tag;
$args = array();
if ( is_array($arg) && 1 == count($arg) && isset($arg[0]) && is_object($arg[0]) ) // array(&$this)
$args[] =& $arg[0];
else
$args[] = $arg;
for ( $a = 2, $num = func_num_args(); $a < $num; $a++ )
$args[] = func_get_arg($a);
$wp_filter[ $tag ]->do_action( $args );
array_pop($wp_current_filter);
}
php
function _wp_call_all_hook($args) {
global $wp_filter;
$wp_filter['all']->do_all_hook( $args );
}
php
function _wp_call_all_hook($args) {
global $wp_filter;
$wp_filter['all']->do_all_hook( $args );
}
php
public function do_all_hook( &$args ) {
//记录回调嵌套
$nesting_level = $this->nesting_level++;
//记录进度
$this->iterations[ $nesting_level ] = array_keys( $this->callbacks );
//current() 是 PHP 中用来获取数组当前元素值的函数
do {
$priority = current( $this->iterations[ $nesting_level ] );
//循环
foreach ( $this->callbacks[ $priority ] as $the_ ) {
//调用
call_user_func_array( $the_['function'], $args );
}
//获取优先级,顺序
} while ( false !== next( $this->iterations[ $nesting_level ] ) );
//清除
//unset是计算机语言中用于销毁变量或函数的构造器,主要应用于PHP和Shell环境。
unset( $this->iterations[ $nesting_level ] );
//调用结束退出
$this->nesting_level--;
}
编辑图片
php
POST /wp-admin/admin-ajax.php HTTP/1.1
Host: wp
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:152.0) Gecko/20100101 Firefox/152.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.9,zh-TW;q=0.8,zh-HK;q=0.7,en-US;q=0.6,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 60
Origin: http://wp
Connection: keep-alive
Referer: http://wp/wp-admin/post-new.php
Cookie: wordpress_3b7f056b9775e5cd94a7cc21da1e2639=admin%7C1784729158%7Co4s2XNop0AdtgOa1jVMrb2P8MkQ4YZrIUcEyGGlJLdu%7C5f3f858286de7410e0ce3272b0c9e9ffa6c3ea76e9a5bdd36fb9069ded0733eb; wordpress_logged_in_3b7f056b9775e5cd94a7cc21da1e2639=admin%7C1784729158%7Co4s2XNop0AdtgOa1jVMrb2P8MkQ4YZrIUcEyGGlJLdu%7Cfd92c6cc37837f548361f25994268c449baf369a95603b04b1c0d5c9297888af; wp-settings-time-1=1783690363; wp-settings-1=libraryContent%3Dbrowse%26align%3Dleft
Priority: u=0
action=image-editor&_ajax_nonce=61116bde13&postid=15&do=open
