<?php
/**
* Media Library uploads for subscription: file-utenti / {user slug} / bonifico | certificato
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class WP_OJS_SSO_Subscription_Media {
public const KIND_BONIFICO = 'bonifico';
public const KIND_CERTIFICATO = 'certificato';
private const BASE_DIR = 'file-utenti';
private static $max_size = 10485760; // 10 MB
private static $allowed_mimes = [ 'application/pdf', 'image/jpeg', 'image/png' ];
/** @var string|null */
private static $filter_subdir = null;
/** @var bool */
private static $bypass_upload_cap = false;
public static function max_size() {
return self::$max_size;
}
public static function allowed_mimes() {
return self::$allowed_mimes;
}
/**
* Public folder under wp-content/uploads: file-utenti/{slug}/bonifico|certificato
*/
public static function get_user_folder_slug( $user_id ) {
$user = get_userdata( (int) $user_id );
if ( ! $user ) {
return 'user-' . (int) $user_id;
}
$slug = sanitize_file_name( $user->user_nicename );
if ( $slug === '' ) {
$slug = 'user-' . (int) $user_id;
}
return $slug;
}
/**
* Relative subdir under basedir, no leading/trailing slash issues (leading slash for subdir in WP is ok).
*/
public static function get_subdir( $user_id, $kind ) {
$slug = self::get_user_folder_slug( $user_id );
return self::BASE_DIR . '/' . $slug . '/' . $kind;
}
/**
* @param string $kind self::KIND_*
*/
public static function handle_upload( $user_id, $file_key, $kind ) {
$user_id = (int) $user_id;
if ( $user_id < 1 || ( self::KIND_BONIFICO !== $kind && self::KIND_CERTIFICATO !== $kind ) ) {
return new WP_Error( 'invalid_args', __( 'Invalid upload request.', 'wp-ojs-sso-bridge' ) );
}
if ( empty( $_FILES[ $file_key ]['name'] ) ) {
return null;
}
$file = $_FILES[ $file_key ];
if ( $file['error'] !== UPLOAD_ERR_OK ) {
return new WP_Error( 'upload_error', __( 'File upload failed.', 'wp-ojs-sso-bridge' ) );
}
if ( $file['size'] > self::$max_size ) {
return new WP_Error( 'file_too_large', __( 'The file exceeds the maximum size of 10 MB.', 'wp-ojs-sso-bridge' ) );
}
$finfo = finfo_open( FILEINFO_MIME_TYPE );
$mimetype = finfo_file( $finfo, $file['tmp_name'] );
finfo_close( $finfo );
if ( ! in_array( $mimetype, self::$allowed_mimes, true ) ) {
return new WP_Error( 'invalid_type', __( 'Only PDF, JPG and PNG files are allowed.', 'wp-ojs-sso-bridge' ) );
}
if ( ! function_exists( 'media_handle_upload' ) ) {
require_once ABSPATH . 'wp-admin/includes/file.php';
require_once ABSPATH . 'wp-admin/includes/image.php';
require_once ABSPATH . 'wp-admin/includes/media.php';
}
$old_attachment_id = self::get_attachment_id( $user_id, $kind );
$old_legacy_path = ( self::KIND_CERTIFICATO === $kind ) ? self::get_legacy_path( $user_id ) : '';
$upload_dir = wp_upload_dir();
$subdir = self::get_subdir( $user_id, $kind );
$abs_target_dir = $upload_dir['basedir'] . '/' . $subdir;
if ( ! is_dir( $abs_target_dir ) ) {
wp_mkdir_p( $abs_target_dir );
}
self::$filter_subdir = $subdir;
add_filter( 'upload_dir', [ __CLASS__, 'filter_upload_dir' ] );
self::$bypass_upload_cap = true;
add_filter( 'user_has_cap', [ __CLASS__, 'filter_user_has_cap' ], 10, 4 );
$prev = get_current_user_id();
wp_set_current_user( $user_id );
// Use default $overrides (test_form => false) so registration without admin POST still works.
$attach_id = media_handle_upload( $file_key, 0 );
wp_set_current_user( $prev );
remove_filter( 'user_has_cap', [ __CLASS__, 'filter_user_has_cap' ], 10 );
self::$bypass_upload_cap = false;
remove_filter( 'upload_dir', [ __CLASS__, 'filter_upload_dir' ] );
self::$filter_subdir = null;
if ( is_wp_error( $attach_id ) ) {
if ( is_array( $file ) && ! empty( $file['name'] ) ) {
// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
error_log( '[wp-ojs-sso-bridge] media upload failed: ' . $attach_id->get_error_message() );
}
return $attach_id;
}
wp_update_post(
[
'ID' => (int) $attach_id,
'post_author' => $user_id,
]
);
if ( $old_attachment_id && (int) $old_attachment_id !== (int) $attach_id ) {
wp_delete_attachment( (int) $old_attachment_id, true );
} elseif ( $old_legacy_path && file_exists( $old_legacy_path ) ) {
@unlink( $old_legacy_path );
}
if ( self::KIND_BONIFICO === $kind ) {
update_user_meta( $user_id, 'ojs_bonifico_attachment_id', (string) (int) $attach_id );
} else {
update_user_meta( $user_id, 'ojs_student_document', (string) (int) $attach_id );
}
return (int) $attach_id;
}
public static function filter_upload_dir( $dirs ) {
if ( ! self::$filter_subdir ) {
return $dirs;
}
$subdir = self::$filter_subdir;
$dirs['subdir'] = '/' . ltrim( $subdir, '/' );
$dirs['path'] = $dirs['basedir'] . $dirs['subdir'];
$dirs['url'] = $dirs['baseurl'] . $dirs['subdir'];
return $dirs;
}
public static function filter_user_has_cap( $allcaps, $caps, $args, $user ) {
if ( ! self::$bypass_upload_cap || empty( $caps ) ) {
return $allcaps;
}
if ( in_array( 'upload_files', (array) $caps, true ) || ( isset( $args[0] ) && 'upload_files' === $args[0] ) ) {
$allcaps['upload_files'] = true;
}
return $allcaps;
}
/**
* @return int|string path for legacy, int attachment id, or empty
*/
public static function get_student_meta_value( $user_id ) {
return get_user_meta( (int) $user_id, 'ojs_student_document', true );
}
/**
* @return int|string
*/
public static function get_legacy_path( $user_id ) {
$v = self::get_student_meta_value( $user_id );
if ( $v && is_string( $v ) && false !== strpos( $v, 'ojs-sso-bridge' ) ) {
return $v;
}
if ( $v && is_string( $v ) && ! is_numeric( $v ) && ( ( false !== strpos( $v, '/' ) && file_exists( $v ) ) || ( false !== strpos( $v, '\\' ) && file_exists( $v ) ) ) ) {
return $v;
}
return '';
}
/**
* @param string $kind KIND_BONIFICO|KIND_CERTIFICATO
*/
public static function get_attachment_id( $user_id, $kind ) {
$user_id = (int) $user_id;
if ( self::KIND_BONIFICO === $kind ) {
$v = get_user_meta( $user_id, 'ojs_bonifico_attachment_id', true );
return ( $v && (int) $v > 0 ) ? (int) $v : 0;
}
$v = self::get_student_meta_value( $user_id );
if ( $v && is_numeric( $v ) && (int) $v > 0 && 'attachment' === get_post_type( (int) $v ) ) {
return (int) $v;
}
return 0;
}
/**
* @param string $kind KIND_*
*/
public static function has_stored_file( $user_id, $kind ) {
if ( self::KIND_BONIFICO === $kind ) {
$id = self::get_attachment_id( $user_id, $kind );
if ( $id > 0 && get_post( $id ) ) {
return true;
}
return false;
}
if ( self::get_attachment_id( $user_id, $kind ) > 0 ) {
return true;
}
$legacy = self::get_legacy_path( $user_id );
return $legacy && is_readable( $legacy );
}
/**
* @param string $kind KIND_*
*/
public static function get_edit_link( $user_id, $kind ) {
$id = self::get_attachment_id( $user_id, $kind );
if ( $id < 1 ) {
return '';
}
if ( current_user_can( 'edit_post', $id ) ) {
$link = get_edit_post_link( $id, 'raw' );
return $link ? $link : '';
}
$url = wp_get_attachment_url( $id );
return $url ? $url : '';
}
/**
* @param string $kind KIND_*
*/
public static function get_file_label( $user_id, $kind ) {
$id = self::get_attachment_id( $user_id, $kind );
if ( $id > 0 ) {
$p = get_post( $id );
return $p ? $p->post_title : (string) $id;
}
if ( self::KIND_CERTIFICATO === $kind ) {
$legacy = self::get_legacy_path( $user_id );
if ( $legacy ) {
return basename( $legacy );
}
}
return '';
}
/**
* @param int[] $user_ids
*/
public static function on_delete_user( $user_id ) {
$user_id = (int) $user_id;
$b = self::get_attachment_id( $user_id, self::KIND_BONIFICO );
if ( $b > 0 ) {
wp_delete_attachment( $b, true );
}
$s = self::get_attachment_id( $user_id, self::KIND_CERTIFICATO );
if ( $s > 0 ) {
wp_delete_attachment( $s, true );
}
$legacy = self::get_legacy_path( $user_id );
if ( $legacy && is_file( $legacy ) ) {
@unlink( $legacy );
}
$old_dir = WP_OJS_SSO_File_Upload::get_upload_dir( $user_id );
if ( is_dir( $old_dir ) ) {
$files = glob( $old_dir . '/*' );
if ( $files ) {
array_map( 'unlink', array_filter( $files, 'is_file' ) );
}
@rmdir( $old_dir );
}
}
}