← All changes
|
inc/rest-api/v1/frontend/class-lp-rest-profile-controller.php
+76
-16
4.3.7
→
4.4.9
View file →
| @@ -1,6 +1,7 @@ | ||
| 1 | 1 | <?php |
| 2 | 2 | |
| 3 | +use LearnPress\Helpers\Response; | |
| 3 | 4 | use LearnPress\Helpers\Template; |
| 4 | 5 | use LearnPress\Models\UserModel; |
| 5 | 6 | |
| 6 | 7 | class LP_REST_Profile_Controller extends LP_Abstract_REST_Controller { |
| @@ -119,8 +120,14 @@ | ||
| 119 | 120 | |
| 120 | 121 | return rest_ensure_response( $response ); |
| 121 | 122 | } |
| 122 | 123 | |
| 124 | + /** | |
| 125 | + * Upload avatar | |
| 126 | + * | |
| 127 | + * @param WP_REST_Request $request | |
| 128 | + * @return WP_Error|WP_HTTP_Response|WP_REST_Response | |
| 129 | + */ | |
| 123 | 130 | public function upload_avatar( WP_REST_Request $request ) { |
| 124 | 131 | $file_base64 = $request->get_param( 'file' ); |
| 125 | 132 | $response = new LP_REST_Response(); |
| 126 | 133 | |
| @@ -129,13 +136,18 @@ | ||
| 129 | 136 | if ( ! $user_id ) { |
| 130 | 137 | throw new Exception( __( 'User not found', 'learnpress' ) ); |
| 131 | 138 | } |
| 132 | 139 | |
| 140 | + $userModel = UserModel::find( $user_id, true ); | |
| 141 | + if ( ! $userModel ) { | |
| 142 | + throw new Exception( __( 'User not found', 'learnpress' ) ); | |
| 143 | + } | |
| 144 | + | |
| 133 | 145 | if ( empty( $file_base64 ) ) { |
| 134 | 146 | throw new Exception( __( 'File not found', 'learnpress' ) ); |
| 135 | 147 | } |
| 136 | 148 | |
| 137 | - $upload_dir = learn_press_user_profile_picture_upload_dir( true ); | |
| 149 | + $upload_dir = learn_press_user_profile_picture_upload_dir(); | |
| 138 | 150 | |
| 139 | 151 | $target_dir = LP_WP_Filesystem::instance()->is_dir( $upload_dir['path'] ); |
| 140 | 152 | |
| 141 | 153 | if ( ! $target_dir ) { |
| @@ -146,12 +158,15 @@ | ||
| 146 | 158 | throw new Exception( __( 'The upload directory is not writable', 'learnpress' ) ); |
| 147 | 159 | } |
| 148 | 160 | |
| 149 | 161 | // Delete old image if exists |
| 150 | - $path_img = get_user_meta( $user_id, '_lp_profile_picture', true ); | |
| 151 | - | |
| 162 | + $path_img = $userModel->get_meta_value_by_key( UserModel::META_KEY_IMAGE ); | |
| 152 | 163 | if ( $path_img ) { |
| 153 | - $path = $upload_dir['basedir'] . '/' . $path_img; | |
| 164 | + if ( 0 === strpos( $path_img, '/' ) ) { | |
| 165 | + $path = $upload_dir['basedir'] . $path_img; | |
| 166 | + } else { | |
| 167 | + $path = trailingslashit( $upload_dir['path'] ) . basename( $path_img ); | |
| 168 | + } | |
| 154 | 169 | |
| 155 | 170 | if ( file_exists( $path ) ) { |
| 156 | 171 | LP_WP_Filesystem::instance()->unlink( $path ); |
| 157 | 172 | } |
| @@ -160,21 +175,60 @@ | ||
| 160 | 175 | $file_name = md5( $user_id . microtime( true ) ) . '.png'; |
| 161 | 176 | |
| 162 | 177 | $file_base64 = str_replace( 'data:image/png;base64,', '', $file_base64 ); |
| 163 | 178 | $file_base64 = base64_decode( $file_base64 ); |
| 179 | + if ( false === $file_base64 ) { | |
| 180 | + throw new Exception( __( 'Invalid avatar image data', 'learnpress' ) ); | |
| 181 | + } | |
| 164 | 182 | |
| 165 | - $put_content = LP_WP_Filesystem::instance()->put_contents( $upload_dir['path'] . '/' . $file_name, $file_base64 ); | |
| 183 | + // Check file size | |
| 184 | + $max_size = wp_max_upload_size(); | |
| 185 | + if ( $max_size > 0 && strlen( $file_base64 ) > $max_size ) { | |
| 186 | + throw new Exception( __( 'Avatar image is too large', 'learnpress' ) ); | |
| 187 | + } | |
| 166 | 188 | |
| 167 | - if ( ! $put_content ) { | |
| 168 | - throw new Exception( __( 'Cannot write the file', 'learnpress' ) ); | |
| 189 | + // Create file temp to check MIME | |
| 190 | + $tmp_file = wp_tempnam(); | |
| 191 | + if ( ! $tmp_file ) { | |
| 192 | + throw new Exception( __( 'Cannot create temporary file', 'learnpress' ) ); | |
| 169 | 193 | } |
| 170 | 194 | |
| 171 | - update_user_meta( $user_id, '_lp_profile_picture', $upload_dir['subdir'] . '/' . $file_name ); | |
| 195 | + $write_tmp = LP_WP_Filesystem::instance()->put_contents( $tmp_file, $file_base64 ); | |
| 196 | + if ( false === $write_tmp ) { | |
| 197 | + LP_WP_Filesystem::instance()->unlink( $tmp_file ); | |
| 198 | + throw new Exception( __( 'Cannot write temporary file', 'learnpress' ) ); | |
| 199 | + } | |
| 200 | + | |
| 201 | + $allowed_mimes = array( | |
| 202 | + 'png' => 'image/png', | |
| 203 | + ); | |
| 204 | + $check = wp_check_filetype_and_ext( $write_tmp, $file_name, $allowed_mimes ); | |
| 205 | + | |
| 206 | + if ( empty( $check['type'] ) ) { | |
| 207 | + throw new Exception( __( 'Invalid avatar image type', 'learnpress' ) ); | |
| 208 | + } | |
| 209 | + | |
| 210 | + if ( ! empty( $check['proper_filename'] ) ) { | |
| 211 | + $file_name = $check['proper_filename']; | |
| 212 | + } | |
| 213 | + | |
| 214 | + // Re-encode the image to strip embedded scripts or malicious metadata. | |
| 215 | + $editor = wp_get_image_editor( $tmp_file ); | |
| 216 | + if ( is_wp_error( $editor ) ) { | |
| 217 | + LP_WP_Filesystem::instance()->unlink( $write_tmp ); | |
| 218 | + throw new Exception( __( 'Cannot create image editor', 'learnpress' ) ); | |
| 219 | + } | |
| 220 | + | |
| 221 | + $editor->set_quality( 100 ); | |
| 222 | + $editor->save( $upload_dir['path'] . '/' . $file_name ); | |
| 223 | + | |
| 224 | + $path_save = trailingslashit( $upload_dir['subdir'] ) . $file_name; | |
| 225 | + $userModel->set_meta_value_by_key( UserModel::META_KEY_IMAGE, $path_save ); | |
| 172 | 226 | do_action( 'learnpress/rest/frontend/profile/upload_avatar', $user_id ); |
| 173 | 227 | |
| 174 | 228 | $response->status = 'success'; |
| 175 | 229 | $response->message = __( 'Avatar updated', 'learnpress' ); |
| 176 | - } catch ( \Throwable $th ) { | |
| 230 | + } catch ( Throwable $th ) { | |
| 177 | 231 | $response->message = $th->getMessage(); |
| 178 | 232 | } |
| 179 | 233 | |
| 180 | 234 | return rest_ensure_response( $response ); |
| @@ -180,9 +234,9 @@ | ||
| 180 | 234 | return rest_ensure_response( $response ); |
| 181 | 235 | } |
| 182 | 236 | |
| 183 | 237 | public function remove_avatar( WP_REST_Request $request ) { |
| 184 | - $response = new LP_REST_Response(); | |
| 238 | + $response = new Response(); | |
| 185 | 239 | |
| 186 | 240 | try { |
| 187 | 241 | $user_id = get_current_user_id(); |
| 188 | 242 | |
| @@ -201,21 +255,27 @@ | ||
| 201 | 255 | if ( ! LP_WP_Filesystem::instance()->is_writable( $upload_dir['path'] ) ) { |
| 202 | 256 | throw new Exception( __( 'The upload directory is not writable', 'learnpress' ) ); |
| 203 | 257 | } |
| 204 | 258 | |
| 205 | - $path_img = get_user_meta( $user_id, '_lp_profile_picture', true ); | |
| 259 | + $path_img = get_user_meta( $user_id, UserModel::META_KEY_IMAGE, true ); | |
| 206 | 260 | |
| 207 | 261 | if ( $path_img ) { |
| 208 | - $path = $upload_dir['basedir'] . '/' . $path_img; | |
| 262 | + if ( 0 === strpos( $path_img, '/' ) ) { | |
| 263 | + $path = $upload_dir['basedir'] . $path_img; | |
| 264 | + } else { | |
| 265 | + $path = trailingslashit( $upload_dir['path'] ) . basename( $path_img ); | |
| 266 | + } | |
| 209 | 267 | |
| 210 | 268 | if ( file_exists( $path ) ) { |
| 211 | 269 | LP_WP_Filesystem::instance()->unlink( $path ); |
| 270 | + } | |
| 212 | 271 | |
| 213 | - $response->status = 'success'; | |
| 214 | - $response->message = esc_html__( 'The profile picture has been removed successfully', 'learnpress' ); | |
| 215 | - } | |
| 272 | + delete_user_meta( $user_id, UserModel::META_KEY_IMAGE ); | |
| 273 | + | |
| 274 | + $response->status = Response::STATUS_SUCCESS; | |
| 275 | + $response->message = esc_html__( 'The profile picture has been removed successfully', 'learnpress' ); | |
| 216 | 276 | } |
| 217 | - } catch ( \Throwable $th ) { | |
| 277 | + } catch ( Throwable $th ) { | |
| 218 | 278 | $response->message = $th->getMessage(); |
| 219 | 279 | } |
| 220 | 280 | |
| 221 | 281 | return rest_ensure_response( $response ); |