分享一个子比主题的小功能:限制用户修改头像的频率,支持普通用户、一级会员、二级会员分别设置“每 X 天最多修改 X 次”。
比如可以设置为:
- 普通用户:每 30 天最多修改 1 次
- 一级会员:每 30 天最多修改 3 次
- 二级会员:每 30 天最多修改 5 次
天数和次数都能自己调整,适合想控制头像频繁更换、给会员增加权益的站点。
功能说明
- 按最近 X 天内的成功修改次数计算,超过限制会提示下次可修改时间。
- 上传失败不扣次数。
- 会员升级、降级或过期后,按当前等级的规则计算,已有记录不会清零。
- 支持限制同时提交,避免通过并发请求绕过次数限制。
- 次数设为
0表示禁止修改,设为-1表示不限次数。

使用方法
将下面代码放到func.php即可
/**
* Zibll 9.1:头像修改次数限制。
* 追加到已有 func.php 时,不要重复粘贴第一行 <?php。
*/
function zal_avatar_rules() {
return array(
0 => array('days' => 30, 'times' => 1), // 普通用户
1 => array('days' => 30, 'times' => 3), // 一级会员
2 => array('days' => 30, 'times' => 5), // 二级会员
);
// days 为正整数;times:0 禁止修改,-1 不限次数。
}
class ZAL_Avatar_Limit {
private static $user_id = 0;
private static $lock_name = '';
public static function check() {
$uid = get_current_user_id();
if (!$uid) { return; } // 未登录由主题处理。
// 无效请求交给主题,避免占用锁。
if (empty($_POST['upload_avatar_nonce']) ||
!wp_verify_nonce($_POST['upload_avatar_nonce'], 'upload_avatar') ||
empty($_FILES['file'])) { return; }
global $wpdb;
$name = 'zal_avatar_' . md5(DB_NAME . ':' . $wpdb->prefix . ':' . $uid);
// 数据库连接级互斥锁;请求退出/连接关闭时释放,不依赖缓存。
if ((string) $wpdb->get_var($wpdb->prepare('SELECT GET_LOCK(%s, 0)', $name)) !== '1') {
self::deny('头像修改正在处理中,请稍后再试。');
}
self::$lock_name = $name;
self::$user_id = $uid;
register_shutdown_function(array(__CLASS__, 'release'));
$rules = zal_avatar_rules();
$level = function_exists('zib_get_user_vip_level') ? (int) zib_get_user_vip_level($uid) : 0;
if (!isset($rules[$level])) { $level = 0; }
$days = max(1, (int) $rules[$level]['days']);
$limit = (int) $rules[$level]['times'];
if ($limit < 0) { return; }
if ($limit === 0) { self::deny('你当前的用户等级暂不允许修改头像。'); }
// 绕过旧的用户元数据缓存,在持锁后读取最新计数。
wp_cache_delete($uid, 'user_meta');
$history = get_user_meta($uid, '_zal_avatar_history', true);
$cutoff = time() - $days * DAY_IN_SECONDS;
$recent = array();
foreach ((array) $history as $stamp) {
if (is_numeric($stamp) && (int) $stamp > $cutoff) { $recent[] = (int) $stamp; }
}
sort($recent, SORT_NUMERIC);
if (count($recent) >= $limit) {
// 降级或调低额度后,也需等到窗口内少于额度才恢复。
$next = $recent[count($recent) - $limit] + $days * DAY_IN_SECONDS;
self::deny(sprintf('最近 %d 天内最多修改头像 %d 次,次数已用完。下次可修改时间:%s。',
$days, $limit, wp_date('Y-m-d H:i', $next)));
}
}
public static function saved($uid) {
if ((int) $uid !== self::$user_id || !self::$lock_name) { return; }
wp_cache_delete($uid, 'user_meta');
$history = get_user_meta($uid, '_zal_avatar_history', true);
$history = is_array($history) ? array_values(array_filter($history, 'is_numeric')) : array();
$history[] = time();
// 保留历史,以便之后增加天数或切换会员等级时重新计算。
update_user_meta($uid, '_zal_avatar_history', $history);
self::release();
}
public static function release() {
if (!self::$lock_name) { return; }
global $wpdb;
$wpdb->get_var($wpdb->prepare('SELECT RELEASE_LOCK(%s)', self::$lock_name));
self::$lock_name = '';
self::$user_id = 0;
}
private static function deny($message) {
self::release();
wp_send_json(array('error' => 1, 'ys' => 'danger', 'msg' => $message));
}
}
add_action('wp_ajax_user_upload_avatar', array('ZAL_Avatar_Limit', 'check'), -100);
add_action('user_save_custom_avatar', array('ZAL_Avatar_Limit', 'saved'), 10, 1);
修改代码顶部的配置即可:
0 => array('days' => 30, 'times' => 1), // 普通用户
1 => array('days' => 30, 'times' => 3), // 一级会员
2 => array('days' => 30, 'times' => 5), // 二级会员
其中,days 是天数,times 是允许修改的次数。例如普通用户每 7 天可修改 2 次,就将对应配置改为:
0 => array('days' => 7, 'times' => 2),
使用前注意
本代码已对照 子比主题 9.1 源码编写,次数从安装代码后开始记录,之前的修改无法追溯。限制针对子比原生前台头像上传功能,其他插件或后台修改头像不在限制范围内。





没有回复内容