added additional plugins
This commit is contained in:
parent
c85895d306
commit
00e60ec1b7
132 changed files with 27514 additions and 0 deletions
|
|
@ -0,0 +1,222 @@
|
|||
<?php
|
||||
/**
|
||||
* Code Renderer Class
|
||||
* Safely renders code content with proper escaping and syntax highlighting
|
||||
*/
|
||||
|
||||
// Prevent direct access
|
||||
if (!defined('WPINC')) {
|
||||
die('Direct access not permitted.');
|
||||
}
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class MCB_Code_Renderer {
|
||||
|
||||
/**
|
||||
* Render code content safely
|
||||
*/
|
||||
public function render_code($content, $filename) {
|
||||
// Validate content before processing
|
||||
$validation = $this->validate_content($content);
|
||||
if (is_wp_error($validation)) {
|
||||
return '<div class="gcv-error">' . esc_html($validation->get_error_message()) . '</div>';
|
||||
}
|
||||
|
||||
// First, ensure the content is treated as plain text
|
||||
// Multiple layers of safety to prevent any code execution
|
||||
|
||||
// 1. Convert to UTF-8 if needed
|
||||
if (!mb_check_encoding($content, 'UTF-8')) {
|
||||
$content = mb_convert_encoding($content, 'UTF-8', mb_detect_encoding($content));
|
||||
}
|
||||
|
||||
// 2. Remove any null bytes
|
||||
$content = str_replace("\0", '', $content);
|
||||
|
||||
// 3. HTML encode everything - this is crucial for safety
|
||||
$safe_content = htmlspecialchars($content, ENT_QUOTES | ENT_HTML5 | ENT_SUBSTITUTE, 'UTF-8', false);
|
||||
|
||||
// 4. Additional escaping for JavaScript context
|
||||
$safe_content = $this->escape_for_javascript($safe_content);
|
||||
|
||||
// 5. Get language for syntax highlighting
|
||||
$language = $this->detect_language($filename);
|
||||
|
||||
// 6. Prepare the code block with line numbers
|
||||
$lines = explode("\n", $safe_content);
|
||||
$formatted_code = $this->format_with_line_numbers($lines);
|
||||
|
||||
// 7. Wrap in proper HTML structure
|
||||
$output = '<div class="gcv-code-container" data-language="' . esc_attr($language) . '">';
|
||||
$output .= '<div class="gcv-code-header">';
|
||||
$output .= '<span class="gcv-filename">' . esc_html(basename($filename)) . '</span>';
|
||||
$output .= '<button class="gcv-copy-btn" data-content="' . esc_attr($safe_content) . '">Copy</button>';
|
||||
$output .= '</div>';
|
||||
$output .= '<div class="gcv-code-wrapper">';
|
||||
$output .= '<pre class="line-numbers"><code class="language-' . esc_attr($language) . '">';
|
||||
$output .= $formatted_code;
|
||||
$output .= '</code></pre>';
|
||||
$output .= '</div>';
|
||||
$output .= '</div>';
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format code with line numbers
|
||||
*/
|
||||
private function format_with_line_numbers($lines) {
|
||||
$output = '';
|
||||
$line_count = count($lines);
|
||||
$digit_count = strlen((string)$line_count);
|
||||
|
||||
foreach ($lines as $index => $line) {
|
||||
$line_num = $index + 1;
|
||||
$padded_num = str_pad($line_num, $digit_count, ' ', STR_PAD_LEFT);
|
||||
$output .= '<span class="line-number" data-line="' . $line_num . '">' . $padded_num . '</span>';
|
||||
$output .= '<span class="line-content">' . $line . '</span>' . "\n";
|
||||
}
|
||||
|
||||
return rtrim($output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Additional escaping for JavaScript context
|
||||
*/
|
||||
private function escape_for_javascript($content) {
|
||||
// Escape any remaining potentially dangerous patterns
|
||||
$patterns = array(
|
||||
'/<script/i' => '<script',
|
||||
'/<\/script/i' => '</script',
|
||||
'/javascript:/i' => 'javascript:',
|
||||
'/on\w+\s*=/i' => 'on_event=',
|
||||
'/<iframe/i' => '<iframe',
|
||||
'/<object/i' => '<object',
|
||||
'/<embed/i' => '<embed',
|
||||
'/<applet/i' => '<applet'
|
||||
);
|
||||
|
||||
foreach ($patterns as $pattern => $replacement) {
|
||||
$content = preg_replace($pattern, $replacement, $content);
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect programming language from filename
|
||||
*/
|
||||
private function detect_language($filename) {
|
||||
$extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
|
||||
$name_lower = strtolower($filename);
|
||||
|
||||
// Map extensions to Prism.js language identifiers
|
||||
$language_map = array(
|
||||
'php' => 'php',
|
||||
'js' => 'javascript',
|
||||
'jsx' => 'jsx',
|
||||
'ts' => 'typescript',
|
||||
'tsx' => 'tsx',
|
||||
'py' => 'python',
|
||||
'rb' => 'ruby',
|
||||
'java' => 'java',
|
||||
'c' => 'c',
|
||||
'cpp' => 'cpp',
|
||||
'cc' => 'cpp',
|
||||
'cxx' => 'cpp',
|
||||
'h' => 'c',
|
||||
'hpp' => 'cpp',
|
||||
'cs' => 'csharp',
|
||||
'swift' => 'swift',
|
||||
'kt' => 'kotlin',
|
||||
'go' => 'go',
|
||||
'rs' => 'rust',
|
||||
'scala' => 'scala',
|
||||
'r' => 'r',
|
||||
'sql' => 'sql',
|
||||
'sh' => 'bash',
|
||||
'bash' => 'bash',
|
||||
'yml' => 'yaml',
|
||||
'yaml' => 'yaml',
|
||||
'json' => 'json',
|
||||
'xml' => 'xml',
|
||||
'html' => 'html',
|
||||
'htm' => 'html',
|
||||
'css' => 'css',
|
||||
'scss' => 'scss',
|
||||
'sass' => 'sass',
|
||||
'less' => 'less',
|
||||
'md' => 'markdown',
|
||||
'markdown' => 'markdown',
|
||||
'txt' => 'plain',
|
||||
'ini' => 'ini',
|
||||
'conf' => 'ini',
|
||||
'cfg' => 'ini'
|
||||
);
|
||||
|
||||
// Special file names
|
||||
if ($name_lower === 'dockerfile') {
|
||||
return 'docker';
|
||||
}
|
||||
if ($name_lower === 'makefile' || $name_lower === 'gnumakefile') {
|
||||
return 'makefile';
|
||||
}
|
||||
if ($name_lower === '.gitignore') {
|
||||
return 'git';
|
||||
}
|
||||
if ($name_lower === '.htaccess') {
|
||||
return 'apacheconf';
|
||||
}
|
||||
if ($name_lower === '.env') {
|
||||
return 'bash';
|
||||
}
|
||||
|
||||
return isset($language_map[$extension]) ? $language_map[$extension] : 'plain';
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize and validate file content before rendering
|
||||
*/
|
||||
public function validate_content($content) {
|
||||
// Check for binary content
|
||||
if ($this->is_binary($content)) {
|
||||
return new WP_Error('binary_file', 'Binary files cannot be displayed');
|
||||
}
|
||||
|
||||
// Check file size (limit to 1MB for performance)
|
||||
if (strlen($content) > 1048576) {
|
||||
return new WP_Error('file_too_large', 'File is too large to display (max 1MB)');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if content appears to be binary
|
||||
*/
|
||||
private function is_binary($content) {
|
||||
// Check for null bytes or excessive non-printable characters
|
||||
$null_count = substr_count($content, "\0");
|
||||
if ($null_count > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Sample first 8192 bytes
|
||||
$sample = substr($content, 0, 8192);
|
||||
$non_printable = 0;
|
||||
|
||||
for ($i = 0; $i < strlen($sample); $i++) {
|
||||
$char = ord($sample[$i]);
|
||||
// Allow common whitespace and printable ASCII
|
||||
if ($char < 32 && $char !== 9 && $char !== 10 && $char !== 13) {
|
||||
$non_printable++;
|
||||
}
|
||||
}
|
||||
|
||||
// If more than 30% non-printable, consider it binary
|
||||
return ($non_printable / strlen($sample)) > 0.3;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue