Файловый менеджер - Редактировать - /home/infrafs/INFRABIKEIT/wp-content/plugins/classes.tar
Назад
class-twenty-twenty-one-customize-color-control.php 0000604 00000002434 15132777320 0016641 0 ustar 00 <?php /** * Customize API: WP_Customize_Color_Control class * * @package WordPress * @subpackage Twenty_Twenty_One * @since Twenty Twenty-One 1.0 */ /** * Customize Color Control class. * * @since Twenty Twenty-One 1.0 * * @see WP_Customize_Control */ class Twenty_Twenty_One_Customize_Color_Control extends WP_Customize_Color_Control { /** * The control type. * * @since Twenty Twenty-One 1.0 * * @var string */ public $type = 'twenty-twenty-one-color'; /** * Colorpicker palette * * @since Twenty Twenty-One 1.0 * * @var array */ public $palette; /** * Enqueue control related scripts/styles. * * @since Twenty Twenty-One 1.0 * * @return void */ public function enqueue() { parent::enqueue(); // Enqueue the script. wp_enqueue_script( 'twentytwentyone-control-color', get_theme_file_uri( 'assets/js/palette-colorpicker.js' ), array( 'customize-controls', 'jquery', 'customize-base', 'wp-color-picker' ), wp_get_theme()->get( 'Version' ), false ); } /** * Refresh the parameters passed to the JavaScript via JSON. * * @since Twenty Twenty-One 1.0 * * @uses WP_Customize_Control::to_json() * * @return void */ public function to_json() { parent::to_json(); $this->json['palette'] = $this->palette; } } class-twenty-twenty-one-customize-notice-control.php 0000604 00000002115 15132777320 0017000 0 ustar 00 <?php /** * Customize API: Twenty_Twenty_One_Customize_Notice_Control class * * @package WordPress * @subpackage Twenty_Twenty_One * @since Twenty Twenty-One 1.0 */ /** * Customize Notice Control class. * * @since Twenty Twenty-One 1.0 * * @see WP_Customize_Control */ class Twenty_Twenty_One_Customize_Notice_Control extends WP_Customize_Control { /** * The control type. * * @since Twenty Twenty-One 1.0 * * @var string */ public $type = 'twenty-twenty-one-notice'; /** * Renders the control content. * * This simply prints the notice we need. * * @since Twenty Twenty-One 1.0 * * @return void */ public function render_content() { ?> <div class="notice notice-warning"> <p><?php esc_html_e( 'To access the Dark Mode settings, select a light background color.', 'twentytwentyone' ); ?></p> <p><a href="<?php echo esc_url( __( 'https://wordpress.org/support/article/twenty-twenty-one/#dark-mode-support', 'twentytwentyone' ) ); ?>"> <?php esc_html_e( 'Learn more about Dark Mode.', 'twentytwentyone' ); ?> </a></p> </div> <?php } } class-twenty-twenty-one-svg-icons.php 0000604 00000147333 15132777320 0013745 0 ustar 00 <?php /** * SVG Icons class * * @package WordPress * @subpackage Twenty_Twenty_One * @since Twenty Twenty-One 1.0 */ /** * This class is in charge of displaying SVG icons across the site. * * Place each <svg> source on its own array key, without adding either * the `width` or `height` attributes, since these are added dynamically, * before rendering the SVG code. * * All icons are assumed to have equal width and height, hence the option * to only specify a `$size` parameter in the svg methods. * * @since Twenty Twenty-One 1.0 */ class Twenty_Twenty_One_SVG_Icons { /** * User Interface icons – svg sources. * * @since Twenty Twenty-One 1.0 * * @var array */ protected static $icons = array( 'arrow_right' => '<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="m4 13v-2h12l-4-4 1-2 7 7-7 7-1-2 4-4z" fill="currentColor"/></svg>', 'arrow_left' => '<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M20 13v-2H8l4-4-1-2-7 7 7 7 1-2-4-4z" fill="currentColor"/></svg>', 'close' => '<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M12 10.9394L5.53033 4.46973L4.46967 5.53039L10.9393 12.0001L4.46967 18.4697L5.53033 19.5304L12 13.0607L18.4697 19.5304L19.5303 18.4697L13.0607 12.0001L19.5303 5.53039L18.4697 4.46973L12 10.9394Z" fill="currentColor"/></svg>', 'menu' => '<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M4.5 6H19.5V7.5H4.5V6ZM4.5 12H19.5V13.5H4.5V12ZM19.5 18H4.5V19.5H19.5V18Z" fill="currentColor"/></svg>', 'plus' => '<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M18 11.2h-5.2V6h-1.6v5.2H6v1.6h5.2V18h1.6v-5.2H18z" fill="currentColor"/></svg>', 'minus' => '<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M6 11h12v2H6z" fill="currentColor"/></svg>', ); /** * Social Icons – svg sources. * * @since Twenty Twenty-One 1.0 * * @var array */ protected static $social_icons = array( '500px' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M6.94026,15.1412c.00437.01213.108.29862.168.44064a6.55008,6.55008,0,1,0,6.03191-9.09557,6.68654,6.68654,0,0,0-2.58357.51467A8.53914,8.53914,0,0,0,8.21268,8.61344L8.209,8.61725V3.22948l9.0504-.00008c.32934-.0036.32934-.46353.32934-.61466s0-.61091-.33035-.61467L7.47248,2a.43.43,0,0,0-.43131.42692v7.58355c0,.24466.30476.42131.58793.4819.553.11812.68074-.05864.81617-.2457l.018-.02481A10.52673,10.52673,0,0,1,9.32258,9.258a5.35268,5.35268,0,1,1,7.58985,7.54976,5.417,5.417,0,0,1-3.80867,1.56365,5.17483,5.17483,0,0,1-2.69822-.74478l.00342-4.61111a2.79372,2.79372,0,0,1,.71372-1.78792,2.61611,2.61611,0,0,1,1.98282-.89477,2.75683,2.75683,0,0,1,1.95525.79477,2.66867,2.66867,0,0,1,.79656,1.909,2.724,2.724,0,0,1-2.75849,2.748,4.94651,4.94651,0,0,1-.86254-.13719c-.31234-.093-.44519.34058-.48892.48349-.16811.54966.08453.65862.13687.67489a3.75751,3.75751,0,0,0,1.25234.18375,3.94634,3.94634,0,1,0-2.82444-6.742,3.67478,3.67478,0,0,0-1.13028,2.584l-.00041.02323c-.0035.11667-.00579,2.881-.00644,3.78811l-.00407-.00451a6.18521,6.18521,0,0,1-1.0851-1.86092c-.10544-.27856-.34358-.22925-.66857-.12917-.14192.04372-.57386.17677-.47833.489Zm4.65165-1.08338a.51346.51346,0,0,0,.19513.31818l.02276.022a.52945.52945,0,0,0,.3517.18416.24242.24242,0,0,0,.16577-.0611c.05473-.05082.67382-.67812.73287-.738l.69041.68819a.28978.28978,0,0,0,.21437.11032.53239.53239,0,0,0,.35708-.19486c.29792-.30419.14885-.46821.07676-.54751l-.69954-.69975.72952-.73469c.16-.17311.01874-.35708-.12218-.498-.20461-.20461-.402-.25742-.52855-.14083l-.7254.72665-.73354-.73375a.20128.20128,0,0,0-.14179-.05695.54135.54135,0,0,0-.34379.19648c-.22561.22555-.274.38149-.15656.5059l.73374.7315-.72942.73072A.26589.26589,0,0,0,11.59191,14.05782Zm1.59866-9.915A8.86081,8.86081,0,0,0,9.854,4.776a.26169.26169,0,0,0-.16938.22759.92978.92978,0,0,0,.08619.42094c.05682.14524.20779.531.50006.41955a8.40969,8.40969,0,0,1,2.91968-.55484,7.87875,7.87875,0,0,1,3.086.62286,8.61817,8.61817,0,0,1,2.30562,1.49315.2781.2781,0,0,0,.18318.07586c.15529,0,.30425-.15253.43167-.29551.21268-.23861.35873-.4369.1492-.63538a8.50425,8.50425,0,0,0-2.62312-1.694A9.0177,9.0177,0,0,0,13.19058,4.14283ZM19.50945,18.6236h0a.93171.93171,0,0,0-.36642-.25406.26589.26589,0,0,0-.27613.06613l-.06943.06929A7.90606,7.90606,0,0,1,7.60639,18.505a7.57284,7.57284,0,0,1-1.696-2.51537,8.58715,8.58715,0,0,1-.5147-1.77754l-.00871-.04864c-.04939-.25873-.28755-.27684-.62981-.22448-.14234.02178-.5755.088-.53426.39969l.001.00712a9.08807,9.08807,0,0,0,15.406,4.99094c.00193-.00192.04753-.04718.0725-.07436C19.79425,19.16234,19.87422,18.98728,19.50945,18.6236Z"></path></svg>', 'amazon' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M13.582,8.182C11.934,8.367,9.78,8.49,8.238,9.166c-1.781,0.769-3.03,2.337-3.03,4.644 c0,2.953,1.86,4.429,4.253,4.429c2.02,0,3.125-0.477,4.685-2.065c0.516,0.747,0.685,1.109,1.629,1.894 c0.212,0.114,0.483,0.103,0.672-0.066l0.006,0.006c0.567-0.505,1.599-1.401,2.18-1.888c0.231-0.188,0.19-0.496,0.009-0.754 c-0.52-0.718-1.072-1.303-1.072-2.634V8.305c0-1.876,0.133-3.599-1.249-4.891C15.23,2.369,13.422,2,12.04,2 C9.336,2,6.318,3.01,5.686,6.351C5.618,6.706,5.877,6.893,6.109,6.945l2.754,0.298C9.121,7.23,9.308,6.977,9.357,6.72 c0.236-1.151,1.2-1.706,2.284-1.706c0.584,0,1.249,0.215,1.595,0.738c0.398,0.584,0.346,1.384,0.346,2.061V8.182z M13.049,14.088 c-0.451,0.8-1.169,1.291-1.967,1.291c-1.09,0-1.728-0.83-1.728-2.061c0-2.42,2.171-2.86,4.227-2.86v0.615 C13.582,12.181,13.608,13.104,13.049,14.088z M20.683,19.339C18.329,21.076,14.917,22,11.979,22c-4.118,0-7.826-1.522-10.632-4.057 c-0.22-0.199-0.024-0.471,0.241-0.317c3.027,1.762,6.771,2.823,10.639,2.823c2.608,0,5.476-0.541,8.115-1.66 C20.739,18.62,21.072,19.051,20.683,19.339z M21.336,21.043c-0.194,0.163-0.379,0.076-0.293-0.139 c0.284-0.71,0.92-2.298,0.619-2.684c-0.301-0.386-1.99-0.183-2.749-0.092c-0.23,0.027-0.266-0.173-0.059-0.319 c1.348-0.946,3.555-0.673,3.811-0.356C22.925,17.773,22.599,19.986,21.336,21.043z"></path></svg>', 'bandcamp' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M15.27 17.289 3 17.289 8.73 6.711 21 6.711 15.27 17.289"></path></svg>', 'behance' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M7.799,5.698c0.589,0,1.12,0.051,1.606,0.156c0.482,0.102,0.894,0.273,1.241,0.507c0.344,0.235,0.612,0.546,0.804,0.938 c0.188,0.387,0.281,0.871,0.281,1.443c0,0.619-0.141,1.137-0.421,1.551c-0.284,0.413-0.7,0.751-1.255,1.014 c0.756,0.218,1.317,0.601,1.689,1.146c0.374,0.549,0.557,1.205,0.557,1.975c0,0.623-0.12,1.161-0.359,1.612 c-0.241,0.457-0.569,0.828-0.973,1.114c-0.408,0.288-0.876,0.5-1.399,0.637C9.052,17.931,8.514,18,7.963,18H2V5.698H7.799 M7.449,10.668c0.481,0,0.878-0.114,1.192-0.345c0.311-0.228,0.463-0.603,0.463-1.119c0-0.286-0.051-0.523-0.152-0.707 C8.848,8.315,8.711,8.171,8.536,8.07C8.362,7.966,8.166,7.894,7.94,7.854c-0.224-0.044-0.457-0.06-0.697-0.06H4.709v2.874H7.449z M7.6,15.905c0.267,0,0.521-0.024,0.759-0.077c0.243-0.053,0.457-0.137,0.637-0.261c0.182-0.12,0.332-0.283,0.441-0.491 C9.547,14.87,9.6,14.602,9.6,14.278c0-0.633-0.18-1.084-0.533-1.357c-0.356-0.27-0.83-0.404-1.413-0.404H4.709v3.388L7.6,15.905z M16.162,15.864c0.367,0.358,0.897,0.538,1.583,0.538c0.493,0,0.92-0.125,1.277-0.374c0.354-0.248,0.571-0.514,0.654-0.79h2.155 c-0.347,1.072-0.872,1.838-1.589,2.299C19.534,18,18.67,18.23,17.662,18.23c-0.701,0-1.332-0.113-1.899-0.337 c-0.567-0.227-1.041-0.544-1.439-0.958c-0.389-0.415-0.689-0.907-0.904-1.484c-0.213-0.574-0.32-1.21-0.32-1.899 c0-0.666,0.11-1.288,0.329-1.863c0.222-0.577,0.529-1.075,0.933-1.492c0.406-0.42,0.885-0.751,1.444-0.994 c0.558-0.241,1.175-0.363,1.857-0.363c0.754,0,1.414,0.145,1.98,0.44c0.563,0.291,1.026,0.686,1.389,1.181 c0.363,0.493,0.622,1.057,0.783,1.69c0.16,0.632,0.217,1.292,0.171,1.983h-6.428C15.557,14.84,15.795,15.506,16.162,15.864 M18.973,11.184c-0.291-0.321-0.783-0.496-1.384-0.496c-0.39,0-0.714,0.066-0.973,0.2c-0.254,0.132-0.461,0.297-0.621,0.491 c-0.157,0.197-0.265,0.405-0.328,0.628c-0.063,0.217-0.101,0.413-0.111,0.587h3.98C19.478,11.969,19.265,11.509,18.973,11.184z M15.057,7.738h4.985V6.524h-4.985L15.057,7.738z"></path></svg>', 'codepen' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M22.016,8.84c-0.002-0.013-0.005-0.025-0.007-0.037c-0.005-0.025-0.008-0.048-0.015-0.072 c-0.003-0.015-0.01-0.028-0.013-0.042c-0.008-0.02-0.015-0.04-0.023-0.062c-0.007-0.015-0.013-0.028-0.02-0.042 c-0.008-0.02-0.018-0.037-0.03-0.057c-0.007-0.013-0.017-0.027-0.025-0.038c-0.012-0.018-0.023-0.035-0.035-0.052 c-0.01-0.013-0.02-0.025-0.03-0.037c-0.015-0.017-0.028-0.032-0.043-0.045c-0.01-0.012-0.022-0.023-0.035-0.035 c-0.015-0.015-0.032-0.028-0.048-0.04c-0.012-0.01-0.025-0.02-0.037-0.03c-0.005-0.003-0.01-0.008-0.015-0.012l-9.161-6.096 c-0.289-0.192-0.666-0.192-0.955,0L2.359,8.237C2.354,8.24,2.349,8.245,2.344,8.249L2.306,8.277 c-0.017,0.013-0.033,0.027-0.048,0.04C2.246,8.331,2.234,8.342,2.222,8.352c-0.015,0.015-0.028,0.03-0.042,0.047 c-0.012,0.013-0.022,0.023-0.03,0.037C2.139,8.453,2.125,8.471,2.115,8.488C2.107,8.501,2.099,8.514,2.09,8.526 C2.079,8.548,2.069,8.565,2.06,8.585C2.054,8.6,2.047,8.613,2.04,8.626C2.032,8.648,2.025,8.67,2.019,8.69 c-0.005,0.013-0.01,0.027-0.013,0.042C1.999,8.755,1.995,8.778,1.99,8.803C1.989,8.817,1.985,8.828,1.984,8.84 C1.978,8.879,1.975,8.915,1.975,8.954v6.093c0,0.037,0.003,0.075,0.008,0.112c0.002,0.012,0.005,0.025,0.007,0.038 c0.005,0.023,0.008,0.047,0.015,0.072c0.003,0.015,0.008,0.028,0.013,0.04c0.007,0.022,0.013,0.042,0.022,0.063 c0.007,0.015,0.013,0.028,0.02,0.04c0.008,0.02,0.018,0.038,0.03,0.058c0.007,0.013,0.015,0.027,0.025,0.038 c0.012,0.018,0.023,0.035,0.035,0.052c0.01,0.013,0.02,0.025,0.03,0.037c0.013,0.015,0.028,0.032,0.042,0.045 c0.012,0.012,0.023,0.023,0.035,0.035c0.015,0.013,0.032,0.028,0.048,0.04l0.038,0.03c0.005,0.003,0.01,0.007,0.013,0.01 l9.163,6.095C11.668,21.953,11.833,22,12,22c0.167,0,0.332-0.047,0.478-0.144l9.163-6.095l0.015-0.01 c0.013-0.01,0.027-0.02,0.037-0.03c0.018-0.013,0.035-0.028,0.048-0.04c0.013-0.012,0.025-0.023,0.035-0.035 c0.017-0.015,0.03-0.032,0.043-0.045c0.01-0.013,0.02-0.025,0.03-0.037c0.013-0.018,0.025-0.035,0.035-0.052 c0.008-0.013,0.018-0.027,0.025-0.038c0.012-0.02,0.022-0.038,0.03-0.058c0.007-0.013,0.013-0.027,0.02-0.04 c0.008-0.022,0.015-0.042,0.023-0.063c0.003-0.013,0.01-0.027,0.013-0.04c0.007-0.025,0.01-0.048,0.015-0.072 c0.002-0.013,0.005-0.027,0.007-0.037c0.003-0.042,0.007-0.079,0.007-0.117V8.954C22.025,8.915,22.022,8.879,22.016,8.84z M12.862,4.464l6.751,4.49l-3.016,2.013l-3.735-2.492V4.464z M11.138,4.464v4.009l-3.735,2.494L4.389,8.954L11.138,4.464z M3.699,10.562L5.853,12l-2.155,1.438V10.562z M11.138,19.536l-6.749-4.491l3.015-2.011l3.735,2.492V19.536z M12,14.035L8.953,12 L12,9.966L15.047,12L12,14.035z M12.862,19.536v-4.009l3.735-2.492l3.016,2.011L12.862,19.536z M20.303,13.438L18.147,12 l2.156-1.438L20.303,13.438z"></path></svg>', 'deviantart' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M 18.19 5.636 18.19 2 18.188 2 14.553 2 14.19 2.366 12.474 5.636 11.935 6 5.81 6 5.81 10.994 9.177 10.994 9.477 11.357 5.81 18.363 5.81 22 5.811 22 9.447 22 9.81 21.634 11.526 18.364 12.065 18 18.19 18 18.19 13.006 14.823 13.006 14.523 12.641 18.19 5.636z"></path></svg>', 'dribbble' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M12,22C6.486,22,2,17.514,2,12S6.486,2,12,2c5.514,0,10,4.486,10,10S17.514,22,12,22z M20.434,13.369 c-0.292-0.092-2.644-0.794-5.32-0.365c1.117,3.07,1.572,5.57,1.659,6.09C18.689,17.798,20.053,15.745,20.434,13.369z M15.336,19.876c-0.127-0.749-0.623-3.361-1.822-6.477c-0.019,0.006-0.038,0.013-0.056,0.019c-4.818,1.679-6.547,5.02-6.701,5.334 c1.448,1.129,3.268,1.803,5.243,1.803C13.183,20.555,14.311,20.313,15.336,19.876z M5.654,17.724 c0.193-0.331,2.538-4.213,6.943-5.637c0.111-0.036,0.224-0.07,0.337-0.102c-0.214-0.485-0.448-0.971-0.692-1.45 c-4.266,1.277-8.405,1.223-8.778,1.216c-0.003,0.087-0.004,0.174-0.004,0.261C3.458,14.207,4.29,16.21,5.654,17.724z M3.639,10.264 c0.382,0.005,3.901,0.02,7.897-1.041c-1.415-2.516-2.942-4.631-3.167-4.94C5.979,5.41,4.193,7.613,3.639,10.264z M9.998,3.709 c0.236,0.316,1.787,2.429,3.187,5c3.037-1.138,4.323-2.867,4.477-3.085C16.154,4.286,14.17,3.471,12,3.471 C11.311,3.471,10.641,3.554,9.998,3.709z M18.612,6.612C18.432,6.855,17,8.69,13.842,9.979c0.199,0.407,0.389,0.821,0.567,1.237 c0.063,0.148,0.124,0.295,0.184,0.441c2.842-0.357,5.666,0.215,5.948,0.275C20.522,9.916,19.801,8.065,18.612,6.612z"></path></svg>', 'dropbox' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M12,6.134L6.069,9.797L2,6.54l5.883-3.843L12,6.134z M2,13.054l5.883,3.843L12,13.459L6.069,9.797L2,13.054z M12,13.459 l4.116,3.439L22,13.054l-4.069-3.257L12,13.459z M22,6.54l-5.884-3.843L12,6.134l5.931,3.663L22,6.54z M12.011,14.2l-4.129,3.426 l-1.767-1.153v1.291l5.896,3.539l5.897-3.539v-1.291l-1.769,1.153L12.011,14.2z"></path></svg>', 'etsy' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M9.16033,4.038c0-.27174.02717-.43478.48913-.43478h6.22283c1.087,0,1.68478.92391,2.11957,2.663l.35326,1.38587h1.05978C19.59511,3.712,19.75815,2,19.75815,2s-2.663.29891-4.23913.29891h-7.962L3.29076,2.163v1.1413L4.731,3.57609c1.00543.19022,1.25.40761,1.33152,1.33152,0,0,.08152,2.71739.08152,7.20109s-.08152,7.17391-.08152,7.17391c0,.81522-.32609,1.11413-1.33152,1.30435l-1.44022.27174V22l4.2663-.13587h7.11957c1.60326,0,5.32609.13587,5.32609.13587.08152-.97826.625-5.40761.70652-5.89674H19.7038L18.644,18.52174c-.84239,1.90217-2.06522,2.038-3.42391,2.038H11.1712c-1.3587,0-2.01087-.54348-2.01087-1.712V12.65217s3.0163,0,3.99457.08152c.76087.05435,1.22283.27174,1.46739,1.33152l.32609,1.413h1.16848l-.08152-3.55978.163-3.587H15.02989l-.38043,1.57609c-.24457,1.03261-.40761,1.22283-1.46739,1.33152-1.38587.13587-4.02174.1087-4.02174.1087Z"></path></svg>', 'facebook' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg>', 'feed' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M2,8.667V12c5.515,0,10,4.485,10,10h3.333C15.333,14.637,9.363,8.667,2,8.667z M2,2v3.333 c9.19,0,16.667,7.477,16.667,16.667H22C22,10.955,13.045,2,2,2z M4.5,17C3.118,17,2,18.12,2,19.5S3.118,22,4.5,22S7,20.88,7,19.5 S5.882,17,4.5,17z"></path></svg>', 'flickr' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M6.5,7c-2.75,0-5,2.25-5,5s2.25,5,5,5s5-2.25,5-5S9.25,7,6.5,7z M17.5,7c-2.75,0-5,2.25-5,5s2.25,5,5,5s5-2.25,5-5 S20.25,7,17.5,7z"></path></svg>', 'foursquare' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M17.573,2c0,0-9.197,0-10.668,0S5,3.107,5,3.805s0,16.948,0,16.948c0,0.785,0.422,1.077,0.66,1.172 c0.238,0.097,0.892,0.177,1.285-0.275c0,0,5.035-5.843,5.122-5.93c0.132-0.132,0.132-0.132,0.262-0.132h3.26 c1.368,0,1.588-0.977,1.732-1.552c0.078-0.318,0.692-3.428,1.225-6.122l0.675-3.368C19.56,2.893,19.14,2,17.573,2z M16.495,7.22 c-0.053,0.252-0.372,0.518-0.665,0.518c-0.293,0-4.157,0-4.157,0c-0.467,0-0.802,0.318-0.802,0.787v0.508 c0,0.467,0.337,0.798,0.805,0.798c0,0,3.197,0,3.528,0s0.655,0.362,0.583,0.715c-0.072,0.353-0.407,2.102-0.448,2.295 c-0.04,0.193-0.262,0.523-0.655,0.523c-0.33,0-2.88,0-2.88,0c-0.523,0-0.683,0.068-1.033,0.503 c-0.35,0.437-3.505,4.223-3.505,4.223c-0.032,0.035-0.063,0.027-0.063-0.015V4.852c0-0.298,0.26-0.648,0.648-0.648 c0,0,8.228,0,8.562,0c0.315,0,0.61,0.297,0.528,0.683L16.495,7.22z"></path></svg>', 'goodreads' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M17.3,17.5c-0.2,0.8-0.5,1.4-1,1.9c-0.4,0.5-1,0.9-1.7,1.2C13.9,20.9,13.1,21,12,21c-0.6,0-1.3-0.1-1.9-0.2 c-0.6-0.1-1.1-0.4-1.6-0.7c-0.5-0.3-0.9-0.7-1.2-1.2c-0.3-0.5-0.5-1.1-0.5-1.7h1.5c0.1,0.5,0.2,0.9,0.5,1.2 c0.2,0.3,0.5,0.6,0.9,0.8c0.3,0.2,0.7,0.3,1.1,0.4c0.4,0.1,0.8,0.1,1.2,0.1c1.4,0,2.5-0.4,3.1-1.2c0.6-0.8,1-2,1-3.5v-1.7h0 c-0.4,0.8-0.9,1.4-1.6,1.9c-0.7,0.5-1.5,0.7-2.4,0.7c-1,0-1.9-0.2-2.6-0.5C8.7,15,8.1,14.5,7.7,14c-0.5-0.6-0.8-1.3-1-2.1 c-0.2-0.8-0.3-1.6-0.3-2.5c0-0.9,0.1-1.7,0.4-2.5c0.3-0.8,0.6-1.5,1.1-2c0.5-0.6,1.1-1,1.8-1.4C10.3,3.2,11.1,3,12,3 c0.5,0,0.9,0.1,1.3,0.2c0.4,0.1,0.8,0.3,1.1,0.5c0.3,0.2,0.6,0.5,0.9,0.8c0.3,0.3,0.5,0.6,0.6,1h0V3.4h1.5V15 C17.6,15.9,17.5,16.7,17.3,17.5z M13.8,14.1c0.5-0.3,0.9-0.7,1.3-1.1c0.3-0.5,0.6-1,0.8-1.6c0.2-0.6,0.3-1.2,0.3-1.9 c0-0.6-0.1-1.2-0.2-1.9c-0.1-0.6-0.4-1.2-0.7-1.7c-0.3-0.5-0.7-0.9-1.3-1.2c-0.5-0.3-1.1-0.5-1.9-0.5s-1.4,0.2-1.9,0.5 c-0.5,0.3-1,0.7-1.3,1.2C8.5,6.4,8.3,7,8.1,7.6C8,8.2,7.9,8.9,7.9,9.5c0,0.6,0.1,1.3,0.2,1.9C8.3,12,8.6,12.5,8.9,13 c0.3,0.5,0.8,0.8,1.3,1.1c0.5,0.3,1.1,0.4,1.9,0.4C12.7,14.5,13.3,14.4,13.8,14.1z"></path></svg>', 'google' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M12.02,10.18v3.72v0.01h5.51c-0.26,1.57-1.67,4.22-5.5,4.22c-3.31,0-6.01-2.75-6.01-6.12s2.7-6.12,6.01-6.12 c1.87,0,3.13,0.8,3.85,1.48l2.84-2.76C16.99,2.99,14.73,2,12.03,2c-5.52,0-10,4.48-10,10s4.48,10,10,10c5.77,0,9.6-4.06,9.6-9.77 c0-0.83-0.11-1.42-0.25-2.05H12.02z"></path></svg>', 'github' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg>', 'instagram' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M12,4.622c2.403,0,2.688,0.009,3.637,0.052c0.877,0.04,1.354,0.187,1.671,0.31c0.42,0.163,0.72,0.358,1.035,0.673 c0.315,0.315,0.51,0.615,0.673,1.035c0.123,0.317,0.27,0.794,0.31,1.671c0.043,0.949,0.052,1.234,0.052,3.637 s-0.009,2.688-0.052,3.637c-0.04,0.877-0.187,1.354-0.31,1.671c-0.163,0.42-0.358,0.72-0.673,1.035 c-0.315,0.315-0.615,0.51-1.035,0.673c-0.317,0.123-0.794,0.27-1.671,0.31c-0.949,0.043-1.233,0.052-3.637,0.052 s-2.688-0.009-3.637-0.052c-0.877-0.04-1.354-0.187-1.671-0.31c-0.42-0.163-0.72-0.358-1.035-0.673 c-0.315-0.315-0.51-0.615-0.673-1.035c-0.123-0.317-0.27-0.794-0.31-1.671C4.631,14.688,4.622,14.403,4.622,12 s0.009-2.688,0.052-3.637c0.04-0.877,0.187-1.354,0.31-1.671c0.163-0.42,0.358-0.72,0.673-1.035 c0.315-0.315,0.615-0.51,1.035-0.673c0.317-0.123,0.794-0.27,1.671-0.31C9.312,4.631,9.597,4.622,12,4.622 M12,3 C9.556,3,9.249,3.01,8.289,3.054C7.331,3.098,6.677,3.25,6.105,3.472C5.513,3.702,5.011,4.01,4.511,4.511 c-0.5,0.5-0.808,1.002-1.038,1.594C3.25,6.677,3.098,7.331,3.054,8.289C3.01,9.249,3,9.556,3,12c0,2.444,0.01,2.751,0.054,3.711 c0.044,0.958,0.196,1.612,0.418,2.185c0.23,0.592,0.538,1.094,1.038,1.594c0.5,0.5,1.002,0.808,1.594,1.038 c0.572,0.222,1.227,0.375,2.185,0.418C9.249,20.99,9.556,21,12,21s2.751-0.01,3.711-0.054c0.958-0.044,1.612-0.196,2.185-0.418 c0.592-0.23,1.094-0.538,1.594-1.038c0.5-0.5,0.808-1.002,1.038-1.594c0.222-0.572,0.375-1.227,0.418-2.185 C20.99,14.751,21,14.444,21,12s-0.01-2.751-0.054-3.711c-0.044-0.958-0.196-1.612-0.418-2.185c-0.23-0.592-0.538-1.094-1.038-1.594 c-0.5-0.5-1.002-0.808-1.594-1.038c-0.572-0.222-1.227-0.375-2.185-0.418C14.751,3.01,14.444,3,12,3L12,3z M12,7.378 c-2.552,0-4.622,2.069-4.622,4.622S9.448,16.622,12,16.622s4.622-2.069,4.622-4.622S14.552,7.378,12,7.378z M12,15 c-1.657,0-3-1.343-3-3s1.343-3,3-3s3,1.343,3,3S13.657,15,12,15z M16.804,6.116c-0.596,0-1.08,0.484-1.08,1.08 s0.484,1.08,1.08,1.08c0.596,0,1.08-0.484,1.08-1.08S17.401,6.116,16.804,6.116z"></path></svg>', 'lastfm' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M10.5002,0 C4.7006,0 0,4.70109753 0,10.4998496 C0,16.2989526 4.7006,21 10.5002,21 C16.299,21 21,16.2989526 21,10.4998496 C21,4.70109753 16.299,0 10.5002,0 Z M14.69735,14.7204413 C13.3164,14.7151781 12.4346,14.0870017 11.83445,12.6859357 L11.6816001,12.3451305 L10.35405,9.31011397 C9.92709997,8.26875064 8.85260001,7.57120012 7.68010001,7.57120012 C6.06945001,7.57120012 4.75925001,8.88509738 4.75925001,10.5009524 C4.75925001,12.1164565 6.06945001,13.4303036 7.68010001,13.4303036 C8.77200001,13.4303036 9.76514999,12.827541 10.2719501,11.8567047 C10.2893,11.8235214 10.3239,11.8019673 10.36305,11.8038219 C10.4007,11.8053759 10.43535,11.8287847 10.4504,11.8631709 L10.98655,13.1045863 C11.0016,13.1389726 10.9956,13.17782 10.97225,13.2068931 C10.1605001,14.1995341 8.96020001,14.7683115 7.68010001,14.7683115 C5.33305,14.7683115 3.42340001,12.8535563 3.42340001,10.5009524 C3.42340001,8.14679459 5.33300001,6.23203946 7.68010001,6.23203946 C9.45720002,6.23203946 10.8909,7.19074535 11.6138,8.86359341 C11.6205501,8.88018505 12.3412,10.5707777 12.97445,12.0190621 C13.34865,12.8739575 13.64615,13.3959676 14.6288,13.4291508 C15.5663001,13.4612814 16.25375,12.9121534 16.25375,12.1484869 C16.25375,11.4691321 15.8320501,11.3003585 14.8803,10.98216 C13.2365,10.4397989 12.34495,9.88605929 12.34495,8.51817658 C12.34495,7.1809207 13.26665,6.31615054 14.692,6.31615054 C15.62875,6.31615054 16.3155,6.7286858 16.79215,7.5768142 C16.80495,7.60062396 16.8079001,7.62814302 16.8004001,7.65420843 C16.7929,7.68027384 16.7748,7.70212868 16.7507001,7.713808 L15.86145,8.16900031 C15.8178001,8.19200805 15.7643,8.17807308 15.73565,8.13847371 C15.43295,7.71345711 15.0956,7.52513451 14.6423,7.52513451 C14.05125,7.52513451 13.6220001,7.92899802 13.6220001,8.48649708 C13.6220001,9.17382194 14.1529001,9.34144259 15.0339,9.61923972 C15.14915,9.65578139 15.26955,9.69397731 15.39385,9.73432853 C16.7763,10.1865133 17.57675,10.7311301 17.57675,12.1836251 C17.57685,13.629654 16.3389,14.7204413 14.69735,14.7204413 Z"></path></svg>', 'linkedin' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg>', 'mail' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M20,4H4C2.895,4,2,4.895,2,6v12c0,1.105,0.895,2,2,2h16c1.105,0,2-0.895,2-2V6C22,4.895,21.105,4,20,4z M20,8.236l-8,4.882 L4,8.236V6h16V8.236z"></path></svg>', 'mastodon' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M23.193 7.879c0-5.206-3.411-6.732-3.411-6.732C18.062.357 15.108.025 12.041 0h-.076c-3.068.025-6.02.357-7.74 1.147 0 0-3.411 1.526-3.411 6.732 0 1.192-.023 2.618.015 4.129.124 5.092.934 10.109 5.641 11.355 2.17.574 4.034.695 5.535.612 2.722-.15 4.25-.972 4.25-.972l-.09-1.975s-1.945.613-4.129.539c-2.165-.074-4.449-.233-4.799-2.891a5.499 5.499 0 0 1-.048-.745s2.125.52 4.817.643c1.646.075 3.19-.097 4.758-.283 3.007-.359 5.625-2.212 5.954-3.905.517-2.665.475-6.507.475-6.507zm-4.024 6.709h-2.497V8.469c0-1.29-.543-1.944-1.628-1.944-1.2 0-1.802.776-1.802 2.312v3.349h-2.483v-3.35c0-1.536-.602-2.312-1.802-2.312-1.085 0-1.628.655-1.628 1.944v6.119H4.832V8.284c0-1.289.328-2.313.987-3.07.68-.758 1.569-1.146 2.674-1.146 1.278 0 2.246.491 2.886 1.474L12 6.585l.622-1.043c.64-.983 1.608-1.474 2.886-1.474 1.104 0 1.994.388 2.674 1.146.658.757.986 1.781.986 3.07v6.304z"/></svg>', 'medium' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M20.962,7.257l-5.457,8.867l-3.923-6.375l3.126-5.08c0.112-0.182,0.319-0.286,0.527-0.286c0.05,0,0.1,0.008,0.149,0.02 c0.039,0.01,0.078,0.023,0.114,0.041l5.43,2.715l0.006,0.003c0.004,0.002,0.007,0.006,0.011,0.008 C20.971,7.191,20.98,7.227,20.962,7.257z M9.86,8.592v5.783l5.14,2.57L9.86,8.592z M15.772,17.331l4.231,2.115 C20.554,19.721,21,19.529,21,19.016V8.835L15.772,17.331z M8.968,7.178L3.665,4.527C3.569,4.479,3.478,4.456,3.395,4.456 C3.163,4.456,3,4.636,3,4.938v11.45c0,0.306,0.224,0.669,0.498,0.806l4.671,2.335c0.12,0.06,0.234,0.088,0.337,0.088 c0.29,0,0.494-0.225,0.494-0.602V7.231C9,7.208,8.988,7.188,8.968,7.178z"></path></svg>', 'meetup' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M19.24775,14.722a3.57032,3.57032,0,0,1-2.94457,3.52073,3.61886,3.61886,0,0,1-.64652.05634c-.07314-.0008-.10187.02846-.12507.09547A2.38881,2.38881,0,0,1,13.49453,20.094a2.33092,2.33092,0,0,1-1.827-.50716.13635.13635,0,0,0-.19878-.00408,3.191,3.191,0,0,1-2.104.60248,3.26309,3.26309,0,0,1-3.00324-2.71993,2.19076,2.19076,0,0,1-.03512-.30865c-.00156-.08579-.03413-.1189-.11608-.13493a2.86421,2.86421,0,0,1-1.23189-.56111,2.945,2.945,0,0,1-1.166-2.05749,2.97484,2.97484,0,0,1,.87524-2.50774.112.112,0,0,0,.02091-.16107,2.7213,2.7213,0,0,1-.36648-1.48A2.81256,2.81256,0,0,1,6.57673,7.58838a.35764.35764,0,0,0,.28869-.22819,4.2208,4.2208,0,0,1,6.02892-1.90111.25161.25161,0,0,0,.22023.0243,3.65608,3.65608,0,0,1,3.76031.90678A3.57244,3.57244,0,0,1,17.95918,8.626a2.97339,2.97339,0,0,1,.01829.57356.10637.10637,0,0,0,.0853.12792,1.97669,1.97669,0,0,1,1.27939,1.33733,2.00266,2.00266,0,0,1-.57112,2.12652c-.05284.05166-.04168.08328-.01173.13489A3.51189,3.51189,0,0,1,19.24775,14.722Zm-6.35959-.27836a1.6984,1.6984,0,0,0,1.14556,1.61113,3.82039,3.82039,0,0,0,1.036.17935,1.46888,1.46888,0,0,0,.73509-.12255.44082.44082,0,0,0,.26057-.44274.45312.45312,0,0,0-.29211-.43375.97191.97191,0,0,0-.20678-.063c-.21326-.03806-.42754-.0701-.63973-.11215a.54787.54787,0,0,1-.50172-.60926,2.75864,2.75864,0,0,1,.1773-.901c.1763-.535.414-1.045.64183-1.55913A12.686,12.686,0,0,0,15.85,10.47863a1.58461,1.58461,0,0,0,.04861-.87208,1.04531,1.04531,0,0,0-.85432-.83981,1.60658,1.60658,0,0,0-1.23654.16594.27593.27593,0,0,1-.36286-.03413c-.085-.0747-.16594-.15379-.24918-.23055a.98682.98682,0,0,0-1.33577-.04933,6.1468,6.1468,0,0,1-.4989.41615.47762.47762,0,0,1-.51535.03566c-.17448-.09307-.35512-.175-.53531-.25665a1.74949,1.74949,0,0,0-.56476-.2016,1.69943,1.69943,0,0,0-1.61654.91787,8.05815,8.05815,0,0,0-.32952.80126c-.45471,1.2557-.82507,2.53825-1.20838,3.81639a1.24151,1.24151,0,0,0,.51532,1.44389,1.42659,1.42659,0,0,0,1.22008.17166,1.09728,1.09728,0,0,0,.66994-.69764c.44145-1.04111.839-2.09989,1.25981-3.14926.11581-.28876.22792-.57874.35078-.86438a.44548.44548,0,0,1,.69189-.19539.50521.50521,0,0,1,.15044.43836,1.75625,1.75625,0,0,1-.14731.50453c-.27379.69219-.55265,1.38236-.82766,2.074a2.0836,2.0836,0,0,0-.14038.42876.50719.50719,0,0,0,.27082.57722.87236.87236,0,0,0,.66145.02739.99137.99137,0,0,0,.53406-.532q.61571-1.20914,1.228-2.42031.28423-.55863.57585-1.1133a.87189.87189,0,0,1,.29055-.35253.34987.34987,0,0,1,.37634-.01265.30291.30291,0,0,1,.12434.31459.56716.56716,0,0,1-.04655.1915c-.05318.12739-.10286.25669-.16183.38156-.34118.71775-.68754,1.43273-1.02568,2.152A2.00213,2.00213,0,0,0,12.88816,14.44366Zm4.78568,5.28972a.88573.88573,0,0,0-1.77139.00465.8857.8857,0,0,0,1.77139-.00465Zm-14.83838-7.296a.84329.84329,0,1,0,.00827-1.68655.8433.8433,0,0,0-.00827,1.68655Zm10.366-9.43673a.83506.83506,0,1,0-.0091,1.67.83505.83505,0,0,0,.0091-1.67Zm6.85014,5.22a.71651.71651,0,0,0-1.433.0093.71656.71656,0,0,0,1.433-.0093ZM5.37528,6.17908A.63823.63823,0,1,0,6.015,5.54483.62292.62292,0,0,0,5.37528,6.17908Zm6.68214,14.80843a.54949.54949,0,1,0-.55052.541A.54556.54556,0,0,0,12.05742,20.98752Zm8.53235-8.49689a.54777.54777,0,0,0-.54027.54023.53327.53327,0,0,0,.532.52293.51548.51548,0,0,0,.53272-.5237A.53187.53187,0,0,0,20.58977,12.49063ZM7.82846,2.4715a.44927.44927,0,1,0,.44484.44766A.43821.43821,0,0,0,7.82846,2.4715Zm13.775,7.60492a.41186.41186,0,0,0-.40065.39623.40178.40178,0,0,0,.40168.40168A.38994.38994,0,0,0,22,10.48172.39946.39946,0,0,0,21.60349,10.07642ZM5.79193,17.96207a.40469.40469,0,0,0-.397-.39646.399.399,0,0,0-.396.405.39234.39234,0,0,0,.39939.389A.39857.39857,0,0,0,5.79193,17.96207Z"></path></svg>', 'pinterest' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M12.289,2C6.617,2,3.606,5.648,3.606,9.622c0,1.846,1.025,4.146,2.666,4.878c0.25,0.111,0.381,0.063,0.439-0.169 c0.044-0.175,0.267-1.029,0.365-1.428c0.032-0.128,0.017-0.237-0.091-0.362C6.445,11.911,6.01,10.75,6.01,9.668 c0-2.777,2.194-5.464,5.933-5.464c3.23,0,5.49,2.108,5.49,5.122c0,3.407-1.794,5.768-4.13,5.768c-1.291,0-2.257-1.021-1.948-2.277 c0.372-1.495,1.089-3.112,1.089-4.191c0-0.967-0.542-1.775-1.663-1.775c-1.319,0-2.379,1.309-2.379,3.059 c0,1.115,0.394,1.869,0.394,1.869s-1.302,5.279-1.54,6.261c-0.405,1.666,0.053,4.368,0.094,4.604 c0.021,0.126,0.167,0.169,0.25,0.063c0.129-0.165,1.699-2.419,2.142-4.051c0.158-0.59,0.817-2.995,0.817-2.995 c0.43,0.784,1.681,1.446,3.013,1.446c3.963,0,6.822-3.494,6.822-7.833C20.394,5.112,16.849,2,12.289,2"></path></svg>', 'pocket' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M21.927,4.194C21.667,3.48,20.982,3,20.222,3h-0.01h-1.721H3.839C3.092,3,2.411,3.47,2.145,4.17 C2.066,4.378,2.026,4.594,2.026,4.814v6.035l0.069,1.2c0.29,2.73,1.707,5.115,3.899,6.778c0.039,0.03,0.079,0.059,0.119,0.089 l0.025,0.018c1.175,0.859,2.491,1.441,3.91,1.727c0.655,0.132,1.325,0.2,1.991,0.2c0.615,0,1.232-0.057,1.839-0.17 c0.073-0.014,0.145-0.028,0.219-0.044c0.02-0.004,0.042-0.012,0.064-0.023c1.359-0.297,2.621-0.864,3.753-1.691l0.025-0.018 c0.04-0.029,0.08-0.058,0.119-0.089c2.192-1.664,3.609-4.049,3.898-6.778l0.069-1.2V4.814C22.026,4.605,22,4.398,21.927,4.194z M17.692,10.481l-4.704,4.512c-0.266,0.254-0.608,0.382-0.949,0.382c-0.342,0-0.684-0.128-0.949-0.382l-4.705-4.512 C5.838,9.957,5.82,9.089,6.344,8.542c0.524-0.547,1.392-0.565,1.939-0.04l3.756,3.601l3.755-3.601 c0.547-0.524,1.415-0.506,1.939,0.04C18.256,9.089,18.238,9.956,17.692,10.481z"></path></svg>', 'reddit' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M22,11.816c0-1.256-1.021-2.277-2.277-2.277c-0.593,0-1.122,0.24-1.526,0.614c-1.481-0.965-3.455-1.594-5.647-1.69 l1.171-3.702l3.18,0.748c0.008,1.028,0.846,1.862,1.876,1.862c1.035,0,1.877-0.842,1.877-1.878c0-1.035-0.842-1.877-1.877-1.877 c-0.769,0-1.431,0.466-1.72,1.13l-3.508-0.826c-0.203-0.047-0.399,0.067-0.46,0.261l-1.35,4.268 c-2.316,0.038-4.411,0.67-5.97,1.671C5.368,9.765,4.853,9.539,4.277,9.539C3.021,9.539,2,10.56,2,11.816 c0,0.814,0.433,1.523,1.078,1.925c-0.037,0.221-0.061,0.444-0.061,0.672c0,3.292,4.011,5.97,8.941,5.97s8.941-2.678,8.941-5.97 c0-0.214-0.02-0.424-0.053-0.632C21.533,13.39,22,12.661,22,11.816z M18.776,4.394c0.606,0,1.1,0.493,1.1,1.1s-0.493,1.1-1.1,1.1 s-1.1-0.494-1.1-1.1S18.169,4.394,18.776,4.394z M2.777,11.816c0-0.827,0.672-1.5,1.499-1.5c0.313,0,0.598,0.103,0.838,0.269 c-0.851,0.676-1.477,1.479-1.812,2.36C2.983,12.672,2.777,12.27,2.777,11.816z M11.959,19.606c-4.501,0-8.164-2.329-8.164-5.193 S7.457,9.22,11.959,9.22s8.164,2.329,8.164,5.193S16.46,19.606,11.959,19.606z M20.636,13.001c-0.326-0.89-0.948-1.701-1.797-2.384 c0.248-0.186,0.55-0.301,0.883-0.301c0.827,0,1.5,0.673,1.5,1.5C21.223,12.299,20.992,12.727,20.636,13.001z M8.996,14.704 c-0.76,0-1.397-0.616-1.397-1.376c0-0.76,0.637-1.397,1.397-1.397c0.76,0,1.376,0.637,1.376,1.397 C10.372,14.088,9.756,14.704,8.996,14.704z M16.401,13.328c0,0.76-0.616,1.376-1.376,1.376c-0.76,0-1.399-0.616-1.399-1.376 c0-0.76,0.639-1.397,1.399-1.397C15.785,11.931,16.401,12.568,16.401,13.328z M15.229,16.708c0.152,0.152,0.152,0.398,0,0.55 c-0.674,0.674-1.727,1.002-3.219,1.002c-0.004,0-0.007-0.002-0.011-0.002c-0.004,0-0.007,0.002-0.011,0.002 c-1.492,0-2.544-0.328-3.218-1.002c-0.152-0.152-0.152-0.398,0-0.55c0.152-0.152,0.399-0.151,0.55,0 c0.521,0.521,1.394,0.775,2.669,0.775c0.004,0,0.007,0.002,0.011,0.002c0.004,0,0.007-0.002,0.011-0.002 c1.275,0,2.148-0.253,2.669-0.775C14.831,16.556,15.078,16.556,15.229,16.708z"></path></svg>', 'skype' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M10.113,2.699c0.033-0.006,0.067-0.013,0.1-0.02c0.033,0.017,0.066,0.033,0.098,0.051L10.113,2.699z M2.72,10.223 c-0.006,0.034-0.011,0.069-0.017,0.103c0.018,0.032,0.033,0.064,0.051,0.095L2.72,10.223z M21.275,13.771 c0.007-0.035,0.011-0.071,0.018-0.106c-0.018-0.031-0.033-0.064-0.052-0.095L21.275,13.771z M13.563,21.199 c0.032,0.019,0.065,0.035,0.096,0.053c0.036-0.006,0.071-0.011,0.105-0.017L13.563,21.199z M22,16.386 c0,1.494-0.581,2.898-1.637,3.953c-1.056,1.057-2.459,1.637-3.953,1.637c-0.967,0-1.914-0.251-2.75-0.725 c0.036-0.006,0.071-0.011,0.105-0.017l-0.202-0.035c0.032,0.019,0.065,0.035,0.096,0.053c-0.543,0.096-1.099,0.147-1.654,0.147 c-1.275,0-2.512-0.25-3.676-0.743c-1.125-0.474-2.135-1.156-3.002-2.023c-0.867-0.867-1.548-1.877-2.023-3.002 c-0.493-1.164-0.743-2.401-0.743-3.676c0-0.546,0.049-1.093,0.142-1.628c0.018,0.032,0.033,0.064,0.051,0.095L2.72,10.223 c-0.006,0.034-0.011,0.069-0.017,0.103C2.244,9.5,2,8.566,2,7.615c0-1.493,0.582-2.898,1.637-3.953 c1.056-1.056,2.46-1.638,3.953-1.638c0.915,0,1.818,0.228,2.622,0.655c-0.033,0.007-0.067,0.013-0.1,0.02l0.199,0.031 c-0.032-0.018-0.066-0.034-0.098-0.051c0.002,0,0.003-0.001,0.004-0.001c0.586-0.112,1.187-0.169,1.788-0.169 c1.275,0,2.512,0.249,3.676,0.742c1.124,0.476,2.135,1.156,3.002,2.024c0.868,0.867,1.548,1.877,2.024,3.002 c0.493,1.164,0.743,2.401,0.743,3.676c0,0.575-0.054,1.15-0.157,1.712c-0.018-0.031-0.033-0.064-0.052-0.095l0.034,0.201 c0.007-0.035,0.011-0.071,0.018-0.106C21.754,14.494,22,15.432,22,16.386z M16.817,14.138c0-1.331-0.613-2.743-3.033-3.282 l-2.209-0.49c-0.84-0.192-1.807-0.444-1.807-1.237c0-0.794,0.679-1.348,1.903-1.348c2.468,0,2.243,1.696,3.468,1.696 c0.645,0,1.209-0.379,1.209-1.031c0-1.521-2.435-2.663-4.5-2.663c-2.242,0-4.63,0.952-4.63,3.488c0,1.221,0.436,2.521,2.839,3.123 l2.984,0.745c0.903,0.223,1.129,0.731,1.129,1.189c0,0.762-0.758,1.507-2.129,1.507c-2.679,0-2.307-2.062-3.743-2.062 c-0.645,0-1.113,0.444-1.113,1.078c0,1.236,1.501,2.886,4.856,2.886C15.236,17.737,16.817,16.199,16.817,14.138z"></path></svg>', 'snapchat' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M12.065,2a5.526,5.526,0,0,1,3.132.892A5.854,5.854,0,0,1,17.326,5.4a5.821,5.821,0,0,1,.351,2.33q0,.612-.117,2.487a.809.809,0,0,0,.365.091,1.93,1.93,0,0,0,.664-.176,1.93,1.93,0,0,1,.664-.176,1.3,1.3,0,0,1,.729.234.7.7,0,0,1,.351.6.839.839,0,0,1-.41.7,2.732,2.732,0,0,1-.9.41,3.192,3.192,0,0,0-.9.378.728.728,0,0,0-.41.618,1.575,1.575,0,0,0,.156.56,6.9,6.9,0,0,0,1.334,1.953,5.6,5.6,0,0,0,1.881,1.315,5.875,5.875,0,0,0,1.042.3.42.42,0,0,1,.365.456q0,.911-2.852,1.341a1.379,1.379,0,0,0-.143.507,1.8,1.8,0,0,1-.182.605.451.451,0,0,1-.429.241,5.878,5.878,0,0,1-.807-.085,5.917,5.917,0,0,0-.833-.085,4.217,4.217,0,0,0-.807.065,2.42,2.42,0,0,0-.82.293,6.682,6.682,0,0,0-.755.5q-.351.267-.755.527a3.886,3.886,0,0,1-.989.436A4.471,4.471,0,0,1,11.831,22a4.307,4.307,0,0,1-1.256-.176,3.784,3.784,0,0,1-.976-.436q-.4-.26-.749-.527a6.682,6.682,0,0,0-.755-.5,2.422,2.422,0,0,0-.807-.293,4.432,4.432,0,0,0-.82-.065,5.089,5.089,0,0,0-.853.1,5,5,0,0,1-.762.1.474.474,0,0,1-.456-.241,1.819,1.819,0,0,1-.182-.618,1.411,1.411,0,0,0-.143-.521q-2.852-.429-2.852-1.341a.42.42,0,0,1,.365-.456,5.793,5.793,0,0,0,1.042-.3,5.524,5.524,0,0,0,1.881-1.315,6.789,6.789,0,0,0,1.334-1.953A1.575,1.575,0,0,0,6,12.9a.728.728,0,0,0-.41-.618,3.323,3.323,0,0,0-.9-.384,2.912,2.912,0,0,1-.9-.41.814.814,0,0,1-.41-.684.71.71,0,0,1,.338-.593,1.208,1.208,0,0,1,.716-.241,1.976,1.976,0,0,1,.625.169,2.008,2.008,0,0,0,.69.169.919.919,0,0,0,.416-.091q-.117-1.849-.117-2.474A5.861,5.861,0,0,1,6.385,5.4,5.516,5.516,0,0,1,8.625,2.819,7.075,7.075,0,0,1,12.062,2Z"></path></svg>', 'soundcloud' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M8.9,16.1L9,14L8.9,9.5c0-0.1,0-0.1-0.1-0.1c0,0-0.1-0.1-0.1-0.1c-0.1,0-0.1,0-0.1,0.1c0,0-0.1,0.1-0.1,0.1L8.3,14l0.1,2.1 c0,0.1,0,0.1,0.1,0.1c0,0,0.1,0.1,0.1,0.1C8.8,16.3,8.9,16.3,8.9,16.1z M11.4,15.9l0.1-1.8L11.4,9c0-0.1,0-0.2-0.1-0.2 c0,0-0.1,0-0.1,0s-0.1,0-0.1,0c-0.1,0-0.1,0.1-0.1,0.2l0,0.1l-0.1,5c0,0,0,0.7,0.1,2v0c0,0.1,0,0.1,0.1,0.1c0.1,0.1,0.1,0.1,0.2,0.1 c0.1,0,0.1,0,0.2-0.1c0.1,0,0.1-0.1,0.1-0.2L11.4,15.9z M2.4,12.9L2.5,14l-0.2,1.1c0,0.1,0,0.1-0.1,0.1c0,0-0.1,0-0.1-0.1L2.1,14 l0.1-1.1C2.2,12.9,2.3,12.9,2.4,12.9C2.3,12.9,2.4,12.9,2.4,12.9z M3.1,12.2L3.3,14l-0.2,1.8c0,0.1,0,0.1-0.1,0.1 c-0.1,0-0.1,0-0.1-0.1L2.8,14L3,12.2C3,12.2,3,12.2,3.1,12.2C3.1,12.2,3.1,12.2,3.1,12.2z M3.9,11.9L4.1,14l-0.2,2.1 c0,0.1,0,0.1-0.1,0.1c-0.1,0-0.1,0-0.1-0.1L3.5,14l0.2-2.1c0-0.1,0-0.1,0.1-0.1C3.9,11.8,3.9,11.8,3.9,11.9z M4.7,11.9L4.9,14 l-0.2,2.1c0,0.1-0.1,0.1-0.1,0.1c-0.1,0-0.1,0-0.1-0.1L4.3,14l0.2-2.2c0-0.1,0-0.1,0.1-0.1C4.7,11.7,4.7,11.8,4.7,11.9z M5.6,12 l0.2,2l-0.2,2.1c0,0.1-0.1,0.1-0.1,0.1c0,0-0.1,0-0.1,0c0,0,0-0.1,0-0.1L5.1,14l0.2-2c0,0,0-0.1,0-0.1s0.1,0,0.1,0 C5.5,11.9,5.5,11.9,5.6,12L5.6,12z M6.4,10.7L6.6,14l-0.2,2.1c0,0,0,0.1,0,0.1c0,0-0.1,0-0.1,0c-0.1,0-0.1-0.1-0.2-0.2L5.9,14 l0.2-3.3c0-0.1,0.1-0.2,0.2-0.2c0,0,0.1,0,0.1,0C6.4,10.7,6.4,10.7,6.4,10.7z M7.2,10l0.2,4.1l-0.2,2.1c0,0,0,0.1,0,0.1 c0,0-0.1,0-0.1,0c-0.1,0-0.2-0.1-0.2-0.2l-0.1-2.1L6.8,10c0-0.1,0.1-0.2,0.2-0.2c0,0,0.1,0,0.1,0S7.2,9.9,7.2,10z M8,9.6L8.2,14 L8,16.1c0,0.1-0.1,0.2-0.2,0.2c-0.1,0-0.2-0.1-0.2-0.2L7.5,14l0.1-4.4c0-0.1,0-0.1,0.1-0.1c0,0,0.1-0.1,0.1-0.1c0.1,0,0.1,0,0.1,0.1 C8,9.6,8,9.6,8,9.6z M11.4,16.1L11.4,16.1L11.4,16.1z M9.7,9.6L9.8,14l-0.1,2.1c0,0.1,0,0.1-0.1,0.2s-0.1,0.1-0.2,0.1 c-0.1,0-0.1,0-0.1-0.1s-0.1-0.1-0.1-0.2L9.2,14l0.1-4.4c0-0.1,0-0.1,0.1-0.2s0.1-0.1,0.2-0.1c0.1,0,0.1,0,0.2,0.1S9.7,9.5,9.7,9.6 L9.7,9.6z M10.6,9.8l0.1,4.3l-0.1,2c0,0.1,0,0.1-0.1,0.2c0,0-0.1,0.1-0.2,0.1c-0.1,0-0.1,0-0.2-0.1c0,0-0.1-0.1-0.1-0.2L10,14 l0.1-4.3c0-0.1,0-0.1,0.1-0.2c0,0,0.1-0.1,0.2-0.1c0.1,0,0.1,0,0.2,0.1S10.6,9.7,10.6,9.8z M12.4,14l-0.1,2c0,0.1,0,0.1-0.1,0.2 c-0.1,0.1-0.1,0.1-0.2,0.1c-0.1,0-0.1,0-0.2-0.1c-0.1-0.1-0.1-0.1-0.1-0.2l-0.1-1l-0.1-1l0.1-5.5v0c0-0.1,0-0.2,0.1-0.2 c0.1,0,0.1-0.1,0.2-0.1c0,0,0.1,0,0.1,0c0.1,0,0.1,0.1,0.1,0.2L12.4,14z M22.1,13.9c0,0.7-0.2,1.3-0.7,1.7c-0.5,0.5-1.1,0.7-1.7,0.7 h-6.8c-0.1,0-0.1,0-0.2-0.1c-0.1-0.1-0.1-0.1-0.1-0.2V8.2c0-0.1,0.1-0.2,0.2-0.3c0.5-0.2,1-0.3,1.6-0.3c1.1,0,2.1,0.4,2.9,1.1 c0.8,0.8,1.3,1.7,1.4,2.8c0.3-0.1,0.6-0.2,1-0.2c0.7,0,1.3,0.2,1.7,0.7C21.8,12.6,22.1,13.2,22.1,13.9L22.1,13.9z"></path></svg>', 'spotify' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M12,2C6.477,2,2,6.477,2,12c0,5.523,4.477,10,10,10c5.523,0,10-4.477,10-10C22,6.477,17.523,2,12,2 M16.586,16.424 c-0.18,0.295-0.563,0.387-0.857,0.207c-2.348-1.435-5.304-1.76-8.785-0.964c-0.335,0.077-0.67-0.133-0.746-0.469 c-0.077-0.335,0.132-0.67,0.469-0.746c3.809-0.871,7.077-0.496,9.713,1.115C16.673,15.746,16.766,16.13,16.586,16.424 M17.81,13.7 c-0.226,0.367-0.706,0.482-1.072,0.257c-2.687-1.652-6.785-2.131-9.965-1.166C6.36,12.917,5.925,12.684,5.8,12.273 C5.675,11.86,5.908,11.425,6.32,11.3c3.632-1.102,8.147-0.568,11.234,1.328C17.92,12.854,18.035,13.335,17.81,13.7 M17.915,10.865 c-3.223-1.914-8.54-2.09-11.618-1.156C5.804,9.859,5.281,9.58,5.131,9.086C4.982,8.591,5.26,8.069,5.755,7.919 c3.532-1.072,9.404-0.865,13.115,1.338c0.445,0.264,0.59,0.838,0.327,1.282C18.933,10.983,18.359,11.129,17.915,10.865"></path></svg>', 'tumblr' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M16.749,17.396c-0.357,0.17-1.041,0.319-1.551,0.332c-1.539,0.041-1.837-1.081-1.85-1.896V9.847h3.861V6.937h-3.847V2.039 c0,0-2.77,0-2.817,0c-0.046,0-0.127,0.041-0.138,0.144c-0.165,1.499-0.867,4.13-3.783,5.181v2.484h1.945v6.282 c0,2.151,1.587,5.206,5.775,5.135c1.413-0.024,2.982-0.616,3.329-1.126L16.749,17.396z"></path></svg>', 'twitch' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M16.499,8.089h-1.636v4.91h1.636V8.089z M12,8.089h-1.637v4.91H12V8.089z M4.228,3.178L3,6.451v13.092h4.499V22h2.456 l2.454-2.456h3.681L21,14.636V3.178H4.228z M19.364,13.816l-2.864,2.865H12l-2.453,2.453V16.68H5.863V4.814h13.501V13.816z"></path></svg>', 'twitter' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M22.23,5.924c-0.736,0.326-1.527,0.547-2.357,0.646c0.847-0.508,1.498-1.312,1.804-2.27 c-0.793,0.47-1.671,0.812-2.606,0.996C18.324,4.498,17.257,4,16.077,4c-2.266,0-4.103,1.837-4.103,4.103 c0,0.322,0.036,0.635,0.106,0.935C8.67,8.867,5.647,7.234,3.623,4.751C3.27,5.357,3.067,6.062,3.067,6.814 c0,1.424,0.724,2.679,1.825,3.415c-0.673-0.021-1.305-0.206-1.859-0.513c0,0.017,0,0.034,0,0.052c0,1.988,1.414,3.647,3.292,4.023 c-0.344,0.094-0.707,0.144-1.081,0.144c-0.264,0-0.521-0.026-0.772-0.074c0.522,1.63,2.038,2.816,3.833,2.85 c-1.404,1.1-3.174,1.756-5.096,1.756c-0.331,0-0.658-0.019-0.979-0.057c1.816,1.164,3.973,1.843,6.29,1.843 c7.547,0,11.675-6.252,11.675-11.675c0-0.178-0.004-0.355-0.012-0.531C20.985,7.47,21.68,6.747,22.23,5.924z"></path></svg>', 'vimeo' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M22.396,7.164c-0.093,2.026-1.507,4.799-4.245,8.32C15.322,19.161,12.928,21,10.97,21c-1.214,0-2.24-1.119-3.079-3.359 c-0.56-2.053-1.119-4.106-1.68-6.159C5.588,9.243,4.921,8.122,4.206,8.122c-0.156,0-0.701,0.328-1.634,0.98L1.594,7.841 c1.027-0.902,2.04-1.805,3.037-2.708C6.001,3.95,7.03,3.327,7.715,3.264c1.619-0.156,2.616,0.951,2.99,3.321 c0.404,2.557,0.685,4.147,0.841,4.769c0.467,2.121,0.981,3.181,1.542,3.181c0.435,0,1.09-0.688,1.963-2.065 c0.871-1.376,1.338-2.422,1.401-3.142c0.125-1.187-0.343-1.782-1.401-1.782c-0.498,0-1.012,0.115-1.541,0.341 c1.023-3.35,2.977-4.977,5.862-4.884C21.511,3.066,22.52,4.453,22.396,7.164z"></path></svg>', 'vk' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M22,7.1c0.2,0.4-0.4,1.5-1.6,3.1c-0.2,0.2-0.4,0.5-0.7,0.9c-0.5,0.7-0.9,1.1-0.9,1.4c-0.1,0.3-0.1,0.6,0.1,0.8 c0.1,0.1,0.4,0.4,0.8,0.9h0l0,0c1,0.9,1.6,1.7,2,2.3c0,0,0,0.1,0.1,0.1c0,0.1,0,0.1,0.1,0.3c0,0.1,0,0.2,0,0.4 c0,0.1-0.1,0.2-0.3,0.3c-0.1,0.1-0.4,0.1-0.6,0.1l-2.7,0c-0.2,0-0.4,0-0.6-0.1c-0.2-0.1-0.4-0.1-0.5-0.2l-0.2-0.1 c-0.2-0.1-0.5-0.4-0.7-0.7s-0.5-0.6-0.7-0.8c-0.2-0.2-0.4-0.4-0.6-0.6C14.8,15,14.6,15,14.4,15c0,0,0,0-0.1,0c0,0-0.1,0.1-0.2,0.2 c-0.1,0.1-0.2,0.2-0.2,0.3c-0.1,0.1-0.1,0.3-0.2,0.5c-0.1,0.2-0.1,0.5-0.1,0.8c0,0.1,0,0.2,0,0.3c0,0.1-0.1,0.2-0.1,0.2l0,0.1 c-0.1,0.1-0.3,0.2-0.6,0.2h-1.2c-0.5,0-1,0-1.5-0.2c-0.5-0.1-1-0.3-1.4-0.6s-0.7-0.5-1.1-0.7s-0.6-0.4-0.7-0.6l-0.3-0.3 c-0.1-0.1-0.2-0.2-0.3-0.3s-0.4-0.5-0.7-0.9s-0.7-1-1.1-1.6c-0.4-0.6-0.8-1.3-1.3-2.2C2.9,9.4,2.5,8.5,2.1,7.5C2,7.4,2,7.3,2,7.2 c0-0.1,0-0.1,0-0.2l0-0.1c0.1-0.1,0.3-0.2,0.6-0.2l2.9,0c0.1,0,0.2,0,0.2,0.1S5.9,6.9,5.9,7L6,7c0.1,0.1,0.2,0.2,0.3,0.3 C6.4,7.7,6.5,8,6.7,8.4C6.9,8.8,7,9,7.1,9.2l0.2,0.3c0.2,0.4,0.4,0.8,0.6,1.1c0.2,0.3,0.4,0.5,0.5,0.7s0.3,0.3,0.4,0.4 c0.1,0.1,0.3,0.1,0.4,0.1c0.1,0,0.2,0,0.3-0.1c0,0,0,0,0.1-0.1c0,0,0.1-0.1,0.1-0.2c0.1-0.1,0.1-0.3,0.1-0.5c0-0.2,0.1-0.5,0.1-0.8 c0-0.4,0-0.8,0-1.3c0-0.3,0-0.5-0.1-0.8c0-0.2-0.1-0.4-0.1-0.5L9.6,7.6C9.4,7.3,9.1,7.2,8.7,7.1C8.6,7.1,8.6,7,8.7,6.9 C8.9,6.7,9,6.6,9.1,6.5c0.4-0.2,1.2-0.3,2.5-0.3c0.6,0,1,0.1,1.4,0.1c0.1,0,0.3,0.1,0.3,0.1c0.1,0.1,0.2,0.1,0.2,0.3 c0,0.1,0.1,0.2,0.1,0.3s0,0.3,0,0.5c0,0.2,0,0.4,0,0.6c0,0.2,0,0.4,0,0.7c0,0.3,0,0.6,0,0.9c0,0.1,0,0.2,0,0.4c0,0.2,0,0.4,0,0.5 c0,0.1,0,0.3,0,0.4s0.1,0.3,0.1,0.4c0.1,0.1,0.1,0.2,0.2,0.3c0.1,0,0.1,0,0.2,0c0.1,0,0.2,0,0.3-0.1c0.1-0.1,0.2-0.2,0.4-0.4 s0.3-0.4,0.5-0.7c0.2-0.3,0.5-0.7,0.7-1.1c0.4-0.7,0.8-1.5,1.1-2.3c0-0.1,0.1-0.1,0.1-0.2c0-0.1,0.1-0.1,0.1-0.1l0,0l0.1,0 c0,0,0,0,0.1,0s0.2,0,0.2,0l3,0c0.3,0,0.5,0,0.7,0S21.9,7,21.9,7L22,7.1z"></path></svg>', 'wordpress' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M12.158,12.786L9.46,20.625c0.806,0.237,1.657,0.366,2.54,0.366c1.047,0,2.051-0.181,2.986-0.51 c-0.024-0.038-0.046-0.079-0.065-0.124L12.158,12.786z M3.009,12c0,3.559,2.068,6.634,5.067,8.092L3.788,8.341 C3.289,9.459,3.009,10.696,3.009,12z M18.069,11.546c0-1.112-0.399-1.881-0.741-2.48c-0.456-0.741-0.883-1.368-0.883-2.109 c0-0.826,0.627-1.596,1.51-1.596c0.04,0,0.078,0.005,0.116,0.007C16.472,3.904,14.34,3.009,12,3.009 c-3.141,0-5.904,1.612-7.512,4.052c0.211,0.007,0.41,0.011,0.579,0.011c0.94,0,2.396-0.114,2.396-0.114 C7.947,6.93,8.004,7.642,7.52,7.699c0,0-0.487,0.057-1.029,0.085l3.274,9.739l1.968-5.901l-1.401-3.838 C9.848,7.756,9.389,7.699,9.389,7.699C8.904,7.67,8.961,6.93,9.446,6.958c0,0,1.484,0.114,2.368,0.114 c0.94,0,2.397-0.114,2.397-0.114c0.485-0.028,0.542,0.684,0.057,0.741c0,0-0.488,0.057-1.029,0.085l3.249,9.665l0.897-2.996 C17.841,13.284,18.069,12.316,18.069,11.546z M19.889,7.686c0.039,0.286,0.06,0.593,0.06,0.924c0,0.912-0.171,1.938-0.684,3.22 l-2.746,7.94c2.673-1.558,4.47-4.454,4.47-7.771C20.991,10.436,20.591,8.967,19.889,7.686z M12,22C6.486,22,2,17.514,2,12 C2,6.486,6.486,2,12,2c5.514,0,10,4.486,10,10C22,17.514,17.514,22,12,22z"></path></svg>', 'yelp' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M12.271,16.718v1.417q-.011,3.257-.067,3.4a.707.707,0,0,1-.569.446,4.637,4.637,0,0,1-2.024-.424A4.609,4.609,0,0,1,7.8,20.565a.844.844,0,0,1-.19-.4.692.692,0,0,1,.044-.29,3.181,3.181,0,0,1,.379-.524q.335-.412,2.019-2.409.011,0,.669-.781a.757.757,0,0,1,.44-.274.965.965,0,0,1,.552.039.945.945,0,0,1,.418.324.732.732,0,0,1,.139.468Zm-1.662-2.8a.783.783,0,0,1-.58.781l-1.339.435q-3.067.981-3.257.981a.711.711,0,0,1-.6-.4,2.636,2.636,0,0,1-.19-.836,9.134,9.134,0,0,1,.011-1.857,3.559,3.559,0,0,1,.335-1.389.659.659,0,0,1,.625-.357,22.629,22.629,0,0,1,2.253.859q.781.324,1.283.524l.937.379a.771.771,0,0,1,.4.34A.982.982,0,0,1,10.609,13.917Zm9.213,3.313a4.467,4.467,0,0,1-1.021,1.8,4.559,4.559,0,0,1-1.512,1.417.671.671,0,0,1-.7-.078q-.156-.112-2.052-3.2l-.524-.859a.761.761,0,0,1-.128-.513.957.957,0,0,1,.217-.513.774.774,0,0,1,.926-.29q.011.011,1.327.446,2.264.736,2.7.887a2.082,2.082,0,0,1,.524.229.673.673,0,0,1,.245.68Zm-7.5-7.049q.056,1.137-.6,1.361-.647.19-1.272-.792L6.237,4.08a.7.7,0,0,1,.212-.691,5.788,5.788,0,0,1,2.314-1,5.928,5.928,0,0,1,2.5-.352.681.681,0,0,1,.547.5q.034.2.245,3.407T12.327,10.181Zm7.384,1.2a.679.679,0,0,1-.29.658q-.167.112-3.67.959-.747.167-1.015.257l.011-.022a.769.769,0,0,1-.513-.044.914.914,0,0,1-.413-.357.786.786,0,0,1,0-.971q.011-.011.836-1.137,1.394-1.908,1.673-2.275a2.423,2.423,0,0,1,.379-.435A.7.7,0,0,1,17.435,8a4.482,4.482,0,0,1,1.372,1.489,4.81,4.81,0,0,1,.9,1.868v.034Z"></path></svg>', 'youtube' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg>', ); /** * Social Icons – domain mappings. * * By default, each Icon ID is matched against a .com TLD. To override this behavior, * specify all the domains it covers (including the .com TLD too, if applicable). * * @since Twenty Twenty-One 1.0 * * @var array */ protected static $social_icons_map = array( 'amazon' => array( 'amazon.com', 'amazon.cn', 'amazon.in', 'amazon.fr', 'amazon.de', 'amazon.it', 'amazon.nl', 'amazon.es', 'amazon.co', 'amazon.ca', ), 'behance' => array( 'behance.net', ), 'codepen' => array( 'codepen.io', ), 'facebook' => array( 'facebook.com', 'fb.me', ), 'feed' => array( 'feed', ), 'lastfm' => array( 'last.fm', ), 'mail' => array( 'mailto:', ), 'pocket' => array( 'getpocket.com', ), 'twitch' => array( 'twitch.tv', ), 'wordpress' => array( 'wordpress.com', 'wordpress.org', ), ); /** * Gets the SVG code for a given icon. * * @static * * @since Twenty Twenty-One 1.0 * * @param string $group The icon group. * @param string $icon The icon. * @param int $size The icon-size in pixels. * @return string */ public static function get_svg( $group, $icon, $size ) { if ( 'ui' === $group ) { $arr = self::$icons; } elseif ( 'social' === $group ) { $arr = self::$social_icons; } else { $arr = array(); } /** * Filters Twenty Twenty-Ones's array of icons. * * The dynamic portion of the hook name, `$group`, refers to * the name of the group of icons, either "ui" or "social". * * @since Twenty Twenty-One 1.0 * * @param array $arr Array of icons. */ $arr = apply_filters( "twenty_twenty_one_svg_icons_{$group}", $arr ); $svg = ''; if ( array_key_exists( $icon, $arr ) ) { $repl = sprintf( '<svg class="svg-icon" width="%d" height="%d" aria-hidden="true" role="img" focusable="false" ', $size, $size ); $svg = preg_replace( '/^<svg /', $repl, trim( $arr[ $icon ] ) ); // Add extra attributes to SVG code. } // @phpstan-ignore-next-line. return $svg; } /** * Detects the social network from a URL and returns the SVG code for its icon. * * @static * * @since Twenty Twenty-One 1.0 * * @param string $uri Social link. * @param int $size The icon-size in pixels. * @return string|null */ public static function get_social_link_svg( $uri, $size ) { static $regex_map; // Only compute regex map once, for performance. if ( ! isset( $regex_map ) ) { $regex_map = array(); /** * Filters Twenty Twenty-Ones's array of domain mappings for social icons. * * By default, each Icon ID is matched against a .com TLD. To override this behavior, * specify all the domains it covers (including the .com TLD too, if applicable). * * @since Twenty Twenty-One 1.0 * * @param array $social_icons_map Array of default social icons. */ $map = apply_filters( 'twenty_twenty_one_social_icons_map', self::$social_icons_map ); /** * Filters Twenty Twenty-One's array of social icons. * * @since Twenty Twenty-One 1.0 * * @param array $social_icons Array of default social icons. */ $social_icons = apply_filters( 'twenty_twenty_one_svg_icons_social', self::$social_icons ); foreach ( array_keys( $social_icons ) as $icon ) { $domains = array_key_exists( $icon, $map ) ? $map[ $icon ] : array( sprintf( '%s.com', $icon ) ); $domains = array_map( 'trim', $domains ); // Remove leading/trailing spaces, to prevent regex from failing to match. $domains = array_map( 'preg_quote', $domains ); $regex_map[ $icon ] = sprintf( '/(%s)/i', implode( '|', $domains ) ); } } foreach ( $regex_map as $icon => $regex ) { if ( preg_match( $regex, $uri ) ) { return self::get_svg( 'social', $icon, $size ) . '<span class="screen-reader-text">'; } } return null; } } class-twenty-twenty-one-customize.php 0000604 00000011512 15132777320 0014044 0 ustar 00 <?php /** * Customizer settings for this theme. * * @package WordPress * @subpackage Twenty_Twenty_One * @since Twenty Twenty-One 1.0 */ if ( ! class_exists( 'Twenty_Twenty_One_Customize' ) ) { /** * Customizer Settings. * * @since Twenty Twenty-One 1.0 */ class Twenty_Twenty_One_Customize { /** * Constructor. Instantiate the object. * * @since Twenty Twenty-One 1.0 */ public function __construct() { add_action( 'customize_register', array( $this, 'register' ) ); } /** * Register customizer options. * * @since Twenty Twenty-One 1.0 * * @param WP_Customize_Manager $wp_customize Theme Customizer object. * @return void */ public function register( $wp_customize ) { // Change site-title & description to postMessage. $wp_customize->get_setting( 'blogname' )->transport = 'postMessage'; // @phpstan-ignore-line. Assume that this setting exists. $wp_customize->get_setting( 'blogdescription' )->transport = 'postMessage'; // @phpstan-ignore-line. Assume that this setting exists. // Add partial for blogname. $wp_customize->selective_refresh->add_partial( 'blogname', array( 'selector' => '.site-title', 'render_callback' => array( $this, 'partial_blogname' ), ) ); // Add partial for blogdescription. $wp_customize->selective_refresh->add_partial( 'blogdescription', array( 'selector' => '.site-description', 'render_callback' => array( $this, 'partial_blogdescription' ), ) ); // Add "display_title_and_tagline" setting for displaying the site-title & tagline. $wp_customize->add_setting( 'display_title_and_tagline', array( 'capability' => 'edit_theme_options', 'default' => true, 'sanitize_callback' => array( __CLASS__, 'sanitize_checkbox' ), ) ); // Add control for the "display_title_and_tagline" setting. $wp_customize->add_control( 'display_title_and_tagline', array( 'type' => 'checkbox', 'section' => 'title_tagline', 'label' => esc_html__( 'Display Site Title & Tagline', 'twentytwentyone' ), ) ); /** * Add excerpt or full text selector to customizer */ $wp_customize->add_section( 'excerpt_settings', array( 'title' => esc_html__( 'Excerpt Settings', 'twentytwentyone' ), 'priority' => 120, ) ); $wp_customize->add_setting( 'display_excerpt_or_full_post', array( 'capability' => 'edit_theme_options', 'default' => 'excerpt', 'sanitize_callback' => function( $value ) { return 'excerpt' === $value || 'full' === $value ? $value : 'excerpt'; }, ) ); $wp_customize->add_control( 'display_excerpt_or_full_post', array( 'type' => 'radio', 'section' => 'excerpt_settings', 'label' => esc_html__( 'On Archive Pages, posts show:', 'twentytwentyone' ), 'choices' => array( 'excerpt' => esc_html__( 'Summary', 'twentytwentyone' ), 'full' => esc_html__( 'Full text', 'twentytwentyone' ), ), ) ); // Background color. // Include the custom control class. include_once get_theme_file_path( 'classes/class-twenty-twenty-one-customize-color-control.php' ); // phpcs:ignore WPThemeReview.CoreFunctionality.FileInclude.FileIncludeFound // Register the custom control. $wp_customize->register_control_type( 'Twenty_Twenty_One_Customize_Color_Control' ); // Get the palette from theme-supports. $palette = get_theme_support( 'editor-color-palette' ); // Build the colors array from theme-support. $colors = array(); if ( isset( $palette[0] ) && is_array( $palette[0] ) ) { foreach ( $palette[0] as $palette_color ) { $colors[] = $palette_color['color']; } } // Add the control. Overrides the default background-color control. $wp_customize->add_control( new Twenty_Twenty_One_Customize_Color_Control( $wp_customize, 'background_color', array( 'label' => esc_html_x( 'Background color', 'Customizer control', 'twentytwentyone' ), 'section' => 'colors', 'palette' => $colors, ) ) ); } /** * Sanitize boolean for checkbox. * * @since Twenty Twenty-One 1.0 * * @param bool $checked Whether or not a box is checked. * @return bool */ public static function sanitize_checkbox( $checked = null ) { return (bool) isset( $checked ) && true === $checked; } /** * Render the site title for the selective refresh partial. * * @since Twenty Twenty-One 1.0 * * @return void */ public function partial_blogname() { bloginfo( 'name' ); } /** * Render the site tagline for the selective refresh partial. * * @since Twenty Twenty-One 1.0 * * @return void */ public function partial_blogdescription() { bloginfo( 'description' ); } } } class-twenty-twenty-one-dark-mode.php 0000604 00000027602 15132777320 0013674 0 ustar 00 <?php /** * Dark Mode Class * * @package WordPress * @subpackage Twenty_Twenty_One * @since Twenty Twenty-One 1.0 */ /** * This class is in charge of Dark Mode. */ class Twenty_Twenty_One_Dark_Mode { /** * Instantiate the object. * * @since Twenty Twenty-One 1.0 */ public function __construct() { // Enqueue assets for the block-editor. add_action( 'enqueue_block_editor_assets', array( $this, 'editor_custom_color_variables' ) ); // Add styles for dark-mode. add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) ); // Add scripts for customizer controls. add_action( 'customize_controls_enqueue_scripts', array( $this, 'customize_controls_enqueue_scripts' ) ); // Add customizer controls. add_action( 'customize_register', array( $this, 'customizer_controls' ) ); // Add HTML classes. add_filter( 'twentytwentyone_html_classes', array( $this, 'html_classes' ) ); // Add classes to <body> in the dashboard. add_filter( 'admin_body_class', array( $this, 'admin_body_classes' ) ); // Add the switch on the frontend & customizer. add_action( 'wp_footer', array( $this, 'the_switch' ) ); // Add the privacy policy content. add_action( 'admin_init', array( $this, 'add_privacy_policy_content' ) ); } /** * Editor custom color variables & scripts. * * @since Twenty Twenty-One 1.0 * * @return void */ public function editor_custom_color_variables() { if ( ! $this->switch_should_render() ) { return; } $background_color = get_theme_mod( 'background_color', 'D1E4DD' ); $should_respect_color_scheme = get_theme_mod( 'respect_user_color_preference', false ); if ( $should_respect_color_scheme && Twenty_Twenty_One_Custom_Colors::get_relative_luminance_from_hex( $background_color ) > 127 ) { // Add Dark Mode variable overrides. wp_add_inline_style( 'twenty-twenty-one-custom-color-overrides', '.is-dark-theme.is-dark-theme .editor-styles-wrapper { --global--color-background: var(--global--color-dark-gray); --global--color-primary: var(--global--color-light-gray); --global--color-secondary: var(--global--color-light-gray); --button--color-text: var(--global--color-background); --button--color-text-hover: var(--global--color-secondary); --button--color-text-active: var(--global--color-secondary); --button--color-background: var(--global--color-secondary); --button--color-background-active: var(--global--color-background); --global--color-border: #9ea1a7; --table--stripes-border-color: rgba(240, 240, 240, 0.15); --table--stripes-background-color: rgba(240, 240, 240, 0.15); }' ); } wp_enqueue_script( 'twentytwentyone-dark-mode-support-toggle', get_template_directory_uri() . '/assets/js/dark-mode-toggler.js', array(), '1.0.0', true ); wp_enqueue_script( 'twentytwentyone-editor-dark-mode-support', get_template_directory_uri() . '/assets/js/editor-dark-mode-support.js', array( 'twentytwentyone-dark-mode-support-toggle' ), '1.0.0', true ); } /** * Enqueue scripts and styles. * * @since Twenty Twenty-One 1.0 * * @return void */ public function enqueue_scripts() { if ( ! $this->switch_should_render() ) { return; } $url = get_template_directory_uri() . '/assets/css/style-dark-mode.css'; if ( is_rtl() ) { $url = get_template_directory_uri() . '/assets/css/style-dark-mode-rtl.css'; } wp_enqueue_style( 'tt1-dark-mode', $url, array( 'twenty-twenty-one-style' ), wp_get_theme()->get( 'Version' ) ); // @phpstan-ignore-line. Version is always a string. } /** * Enqueue scripts for the customizer. * * @since Twenty Twenty-One 1.0 * * @return void */ public function customize_controls_enqueue_scripts() { if ( ! $this->switch_should_render() ) { return; } wp_enqueue_script( 'twentytwentyone-customize-controls', get_template_directory_uri() . '/assets/js/customize.js', array( 'customize-base', 'customize-controls', 'underscore', 'jquery', 'twentytwentyone-customize-helpers' ), '1.0.0', true ); } /** * Register customizer options. * * @since Twenty Twenty-One 1.0 * * @param WP_Customize_Manager $wp_customize Theme Customizer object. * @return void */ public function customizer_controls( $wp_customize ) { $colors_section = $wp_customize->get_section( 'colors' ); if ( is_object( $colors_section ) ) { $colors_section->title = __( 'Colors & Dark Mode', 'twentytwentyone' ); } // Custom notice control. include_once get_theme_file_path( 'classes/class-twenty-twenty-one-customize-notice-control.php' ); // phpcs:ignore WPThemeReview.CoreFunctionality.FileInclude.FileIncludeFound $wp_customize->add_setting( 'respect_user_color_preference_notice', array( 'capability' => 'edit_theme_options', 'default' => '', 'sanitize_callback' => '__return_empty_string', ) ); $wp_customize->add_control( new Twenty_Twenty_One_Customize_Notice_Control( $wp_customize, 'respect_user_color_preference_notice', array( 'section' => 'colors', 'priority' => 100, 'active_callback' => function() { return 127 >= Twenty_Twenty_One_Custom_Colors::get_relative_luminance_from_hex( get_theme_mod( 'background_color', 'D1E4DD' ) ); }, ) ) ); $wp_customize->add_setting( 'respect_user_color_preference', array( 'capability' => 'edit_theme_options', 'default' => false, 'sanitize_callback' => function( $value ) { return (bool) $value; }, ) ); $description = '<p>'; $description .= sprintf( /* translators: %s: Twenty Twenty-One support article URL. */ __( 'Dark Mode is a device setting. If a visitor to your site requests it, your site will be shown with a dark background and light text. <a href="%s">Learn more about Dark Mode.</a>', 'twentytwentyone' ), esc_url( __( 'https://wordpress.org/support/article/twenty-twenty-one/#dark-mode-support', 'twentytwentyone' ) ) ); $description .= '</p>'; $description .= '<p>' . __( 'Dark Mode can also be turned on and off with a button that you can find in the bottom right corner of the page.', 'twentytwentyone' ) . '</p>'; $wp_customize->add_control( 'respect_user_color_preference', array( 'type' => 'checkbox', 'section' => 'colors', 'label' => esc_html__( 'Dark Mode support', 'twentytwentyone' ), 'priority' => 110, 'description' => $description, 'active_callback' => function( $value ) { return 127 < Twenty_Twenty_One_Custom_Colors::get_relative_luminance_from_hex( get_theme_mod( 'background_color', 'D1E4DD' ) ); }, ) ); // Add partial for background_color. $wp_customize->selective_refresh->add_partial( 'background_color', array( 'selector' => '#dark-mode-toggler', 'container_inclusive' => true, 'render_callback' => function() { $attrs = ( $this->switch_should_render() ) ? array() : array( 'style' => 'display:none;' ); $this->the_html( $attrs ); }, ) ); } /** * Calculate classes for the main <html> element. * * @since Twenty Twenty-One 1.0 * * @param string $classes The classes for <html> element. * @return string */ public function html_classes( $classes ) { if ( ! $this->switch_should_render() ) { return $classes; } $background_color = get_theme_mod( 'background_color', 'D1E4DD' ); $should_respect_color_scheme = get_theme_mod( 'respect_user_color_preference', false ); if ( $should_respect_color_scheme && 127 <= Twenty_Twenty_One_Custom_Colors::get_relative_luminance_from_hex( $background_color ) ) { return ( $classes ) ? ' respect-color-scheme-preference' : 'respect-color-scheme-preference'; } return $classes; } /** * Adds a class to the <body> element in the editor to accommodate dark-mode. * * @since Twenty Twenty-One 1.0 * * @param string $classes The admin body-classes. * @return string */ public function admin_body_classes( $classes ) { if ( ! $this->switch_should_render() ) { return $classes; } global $current_screen; if ( empty( $current_screen ) ) { set_current_screen(); } if ( $current_screen->is_block_editor() ) { $should_respect_color_scheme = get_theme_mod( 'respect_user_color_preference', false ); $background_color = get_theme_mod( 'background_color', 'D1E4DD' ); if ( $should_respect_color_scheme && Twenty_Twenty_One_Custom_Colors::get_relative_luminance_from_hex( $background_color ) > 127 ) { $classes .= ' twentytwentyone-supports-dark-theme'; } } return $classes; } /** * Determine if we want to print the dark-mode switch or not. * * @since Twenty Twenty-One 1.0 * * @return bool */ public function switch_should_render() { global $is_IE; return ( get_theme_mod( 'respect_user_color_preference', false ) && ! $is_IE && 127 <= Twenty_Twenty_One_Custom_Colors::get_relative_luminance_from_hex( get_theme_mod( 'background_color', 'D1E4DD' ) ) ); } /** * Add night/day switch. * * @since Twenty Twenty-One 1.0 * * @return void */ public function the_switch() { if ( ! $this->switch_should_render() ) { return; } $this->the_html(); $this->the_script(); } /** * Print the dark-mode switch HTML. * * Inspired from https://codepen.io/aaroniker/pen/KGpXZo (MIT-licensed) * * @since Twenty Twenty-One 1.0 * * @param array $attrs The attributes to add to our <button> element. * @return void */ public function the_html( $attrs = array() ) { $attrs = wp_parse_args( $attrs, array( 'id' => 'dark-mode-toggler', 'class' => 'fixed-bottom', 'aria-pressed' => 'false', 'onClick' => 'toggleDarkMode()', ) ); echo '<button'; foreach ( $attrs as $key => $val ) { echo ' ' . esc_attr( $key ) . '="' . esc_attr( $val ) . '"'; } echo '>'; printf( /* translators: %s: On/Off */ esc_html__( 'Dark Mode: %s', 'twentytwentyone' ), '<span aria-hidden="true"></span>' ); echo '</button>'; ?> <style> #dark-mode-toggler > span { margin-<?php echo is_rtl() ? 'right' : 'left'; ?>: 5px; } #dark-mode-toggler > span::before { content: '<?php esc_attr_e( 'Off', 'twentytwentyone' ); ?>'; } #dark-mode-toggler[aria-pressed="true"] > span::before { content: '<?php esc_attr_e( 'On', 'twentytwentyone' ); ?>'; } <?php if ( is_admin() || wp_is_json_request() ) : ?> .components-editor-notices__pinned ~ .edit-post-visual-editor #dark-mode-toggler { z-index: 20; } .is-dark-theme.is-dark-theme #dark-mode-toggler:not(:hover):not(:focus) { color: var(--global--color-primary); } @media only screen and (max-width: 782px) { #dark-mode-toggler { margin-top: 32px; } } <?php endif; ?> </style> <?php } /** * Print the dark-mode switch script. * * @since Twenty Twenty-One 1.0 * * @return void */ public function the_script() { echo '<script>'; include get_template_directory() . '/assets/js/dark-mode-toggler.js'; // phpcs:ignore WPThemeReview.CoreFunctionality.FileInclude echo '</script>'; } /** * Adds information to the privacy policy. * * @since Twenty Twenty-One 1.0 * * @return void */ public function add_privacy_policy_content() { if ( ! function_exists( 'wp_add_privacy_policy_content' ) ) { return; } $content = '<p class="privacy-policy-tutorial">' . __( 'Twenty Twenty-One uses LocalStorage when Dark Mode support is enabled.', 'twentytwentyone' ) . '</p>' . '<strong class="privacy-policy-tutorial">' . __( 'Suggested text:', 'twentytwentyone' ) . '</strong> ' . __( 'This website uses LocalStorage to save the setting when Dark Mode support is turned on or off.<br> LocalStorage is necessary for the setting to work and is only used when a user clicks on the Dark Mode button.<br> No data is saved in the database or transferred.', 'twentytwentyone' ); wp_add_privacy_policy_content( 'Twenty Twenty-One', wp_kses_post( wpautop( $content, false ) ) ); } } class-twenty-twenty-one-custom-colors.php 0000604 00000011664 15132777320 0014643 0 ustar 00 <?php /** * Custom Colors Class * * @package WordPress * @subpackage Twenty_Twenty_One * @since Twenty Twenty-One 1.0 */ /** * This class is in charge of color customization via the Customizer. */ class Twenty_Twenty_One_Custom_Colors { /** * Instantiate the object. * * @since Twenty Twenty-One 1.0 */ public function __construct() { // Enqueue color variables for customizer & frontend. add_action( 'wp_enqueue_scripts', array( $this, 'custom_color_variables' ) ); // Enqueue color variables for editor. add_action( 'enqueue_block_editor_assets', array( $this, 'editor_custom_color_variables' ) ); // Add body-class if needed. add_filter( 'body_class', array( $this, 'body_class' ) ); } /** * Determine the luminance of the given color and then return #fff or #000 so that the text is always readable. * * @since Twenty Twenty-One 1.0 * * @param string $background_color The background color. * @return string (hex color) */ public function custom_get_readable_color( $background_color ) { return ( 127 < self::get_relative_luminance_from_hex( $background_color ) ) ? '#000' : '#fff'; } /** * Generate color variables. * * Adjust the color value of the CSS variables depending on the background color theme mod. * Both text and link colors needs to be updated. * The code below needs to be updated, because the colors are no longer theme mods. * * @since Twenty Twenty-One 1.0 * * @param string|null $context Can be "editor" or null. * @return string */ public function generate_custom_color_variables( $context = null ) { $theme_css = 'editor' === $context ? ':root .editor-styles-wrapper{' : ':root{'; $background_color = get_theme_mod( 'background_color', 'D1E4DD' ); if ( 'd1e4dd' !== strtolower( $background_color ) ) { $theme_css .= '--global--color-background: #' . $background_color . ';'; $theme_css .= '--global--color-primary: ' . $this->custom_get_readable_color( $background_color ) . ';'; $theme_css .= '--global--color-secondary: ' . $this->custom_get_readable_color( $background_color ) . ';'; $theme_css .= '--button--color-background: ' . $this->custom_get_readable_color( $background_color ) . ';'; $theme_css .= '--button--color-text-hover: ' . $this->custom_get_readable_color( $background_color ) . ';'; if ( '#fff' === $this->custom_get_readable_color( $background_color ) ) { $theme_css .= '--table--stripes-border-color: rgba(240, 240, 240, 0.15);'; $theme_css .= '--table--stripes-background-color: rgba(240, 240, 240, 0.15);'; } } $theme_css .= '}'; return $theme_css; } /** * Customizer & frontend custom color variables. * * @since Twenty Twenty-One 1.0 * * @return void */ public function custom_color_variables() { if ( 'd1e4dd' !== strtolower( get_theme_mod( 'background_color', 'D1E4DD' ) ) ) { wp_add_inline_style( 'twenty-twenty-one-style', $this->generate_custom_color_variables() ); } } /** * Editor custom color variables. * * @since Twenty Twenty-One 1.0 * * @return void */ public function editor_custom_color_variables() { wp_enqueue_style( 'twenty-twenty-one-custom-color-overrides', get_theme_file_uri( 'assets/css/custom-color-overrides.css' ), array(), wp_get_theme()->get( 'Version' ) ); $background_color = get_theme_mod( 'background_color', 'D1E4DD' ); if ( 'd1e4dd' !== strtolower( $background_color ) ) { wp_add_inline_style( 'twenty-twenty-one-custom-color-overrides', $this->generate_custom_color_variables( 'editor' ) ); } } /** * Get luminance from a HEX color. * * @static * * @since Twenty Twenty-One 1.0 * * @param string $hex The HEX color. * @return int Returns a number (0-255). */ public static function get_relative_luminance_from_hex( $hex ) { // Remove the "#" symbol from the beginning of the color. $hex = ltrim( $hex, '#' ); // Make sure there are 6 digits for the below calculations. if ( 3 === strlen( $hex ) ) { $hex = substr( $hex, 0, 1 ) . substr( $hex, 0, 1 ) . substr( $hex, 1, 1 ) . substr( $hex, 1, 1 ) . substr( $hex, 2, 1 ) . substr( $hex, 2, 1 ); } // Get red, green, blue. $red = hexdec( substr( $hex, 0, 2 ) ); $green = hexdec( substr( $hex, 2, 2 ) ); $blue = hexdec( substr( $hex, 4, 2 ) ); // Calculate the luminance. $lum = ( 0.2126 * $red ) + ( 0.7152 * $green ) + ( 0.0722 * $blue ); return (int) round( $lum ); } /** * Adds a class to <body> if the background-color is dark. * * @since Twenty Twenty-One 1.0 * * @param array $classes The existing body classes. * @return array */ public function body_class( $classes ) { $background_color = get_theme_mod( 'background_color', 'D1E4DD' ); $luminance = self::get_relative_luminance_from_hex( $background_color ); if ( 127 > $luminance ) { $classes[] = 'is-dark-theme'; } else { $classes[] = 'is-light-theme'; } if ( 225 <= $luminance ) { $classes[] = 'has-background-white'; } return $classes; } } package/index.php 0000644 00000000016 15133151516 0007755 0 ustar 00 <?php //silent package/class.pack.archive.php 0000644 00000070205 15133151516 0012317 0 ustar 00 <?php defined('ABSPATH') || defined('DUPXABSPATH') || exit; // Exit if accessed directly if (!defined('DUPLICATOR_VERSION')) exit; require_once (DUPLICATOR_PLUGIN_PATH.'classes/package/duparchive/class.pack.archive.duparchive.php'); require_once (DUPLICATOR_PLUGIN_PATH.'classes/package/class.pack.archive.filters.php'); require_once (DUPLICATOR_PLUGIN_PATH.'classes/package/class.pack.archive.zip.php'); require_once (DUPLICATOR_PLUGIN_PATH.'lib/forceutf8/Encoding.php'); /** * Class for handling archive setup and build process * * Standard: PSR-2 (almost) * @link http://www.php-fig.org/psr/psr-2 * * @package DUP * @subpackage classes/package * @copyright (c) 2017, Snapcreek LLC * @license https://opensource.org/licenses/GPL-3.0 GNU Public License * */ class DUP_Archive { //PUBLIC public $FilterDirs; public $FilterFiles; public $FilterExts; public $FilterDirsAll = array(); public $FilterFilesAll = array(); public $FilterExtsAll = array(); public $FilterOn; public $ExportOnlyDB; public $File; public $Format; public $PackDir; public $Size = 0; public $Dirs = array(); public $Files = array(); /** * * @var DUP_Archive_Filter_Info */ public $FilterInfo = null; public $RecursiveLinks = array(); public $file_count = -1; //PROTECTED protected $Package; private $tmpFilterDirsAll = array(); private $wpCorePaths = array(); private $wpCoreExactPaths = array(); /** * Init this object */ public function __construct($package) { $this->Package = $package; $this->FilterOn = false; $this->ExportOnlyDB = false; $this->FilterInfo = new DUP_Archive_Filter_Info(); $homePath = duplicator_get_home_path(); $this->wpCorePaths[] = DUP_Util::safePath("{$homePath}/wp-admin"); $this->wpCorePaths[] = DUP_Util::safePath(WP_CONTENT_DIR."/languages"); $this->wpCorePaths[] = DUP_Util::safePath("{$homePath}/wp-includes"); $this->wpCoreExactPaths[] = DUP_Util::safePath("{$homePath}"); $this->wpCoreExactPaths[] = DUP_Util::safePath(WP_CONTENT_DIR); $this->wpCoreExactPaths[] = DUP_Util::safePath(WP_CONTENT_DIR."/uploads"); $this->wpCoreExactPaths[] = DUP_Util::safePath(WP_CONTENT_DIR."/plugins"); $this->wpCoreExactPaths[] = DUP_Util::safePath(get_theme_root()); } /** * Builds the archive based on the archive type * * @param obj $package The package object that started this process * * @return null */ public function build($package, $rethrow_exception = false) { DUP_LOG::trace("b1"); $this->Package = $package; if (!isset($this->PackDir) && !is_dir($this->PackDir)) throw new Exception("The 'PackDir' property must be a valid directory."); if (!isset($this->File)) throw new Exception("A 'File' property must be set."); DUP_LOG::trace("b2"); $completed = false; switch ($this->Format) { case 'TAR': break; case 'TAR-GZIP': break; case 'DAF': $completed = DUP_DupArchive::create($this, $this->Package->BuildProgress, $this->Package); $this->Package->Update(); break; default: if (class_exists('ZipArchive')) { $this->Format = 'ZIP'; DUP_Zip::create($this, $this->Package->BuildProgress); $completed = true; } break; } DUP_LOG::Trace("Completed build or build thread"); if ($this->Package->BuildProgress === null) { // Zip path DUP_LOG::Trace("Completed Zip"); $storePath = DUP_Settings::getSsdirTmpPath()."/{$this->File}"; $this->Size = @filesize($storePath); $this->Package->setStatus(DUP_PackageStatus::ARCDONE); } else if ($completed) { // Completed DupArchive path DUP_LOG::Trace("Completed DupArchive build"); if ($this->Package->BuildProgress->failed) { DUP_LOG::Trace("Error building DupArchive"); $this->Package->setStatus(DUP_PackageStatus::ERROR); } else { $filepath = DUP_Settings::getSsdirTmpPath()."/{$this->File}"; $this->Size = @filesize($filepath); $this->Package->setStatus(DUP_PackageStatus::ARCDONE); DUP_LOG::Trace("Done building archive"); } } else { DUP_Log::trace("DupArchive chunk done but package not completed yet"); } } /** * * @return int return DUP_Archive_Build_Mode */ public function getBuildMode() { switch ($this->Format) { case 'TAR': break; case 'TAR-GZIP': break; case 'DAF': return DUP_Archive_Build_Mode::DupArchive; default: if (class_exists('ZipArchive')) { return DUP_Archive_Build_Mode::ZipArchive; } else { return DUP_Archive_Build_Mode::Unconfigured; } break; } } /** * Builds a list of files and directories to be included in the archive * * Get the directory size recursively, but don't calc the snapshot directory, exclusion directories * @link http://msdn.microsoft.com/en-us/library/aa365247%28VS.85%29.aspx Windows filename restrictions * * @return obj Returns a DUP_Archive object */ public function getScannerData() { $this->createFilterInfo(); $rootPath = duplicator_get_abs_path(); $this->RecursiveLinks = array(); //If the root directory is a filter then skip it all if (in_array($this->PackDir, $this->FilterDirsAll) || $this->Package->Archive->ExportOnlyDB) { $this->Dirs = array(); } else { $this->Dirs[] = $this->PackDir; $this->getFileLists($rootPath); if ($this->isOuterWPContentDir()) { $this->Dirs[] = WP_CONTENT_DIR; $this->getFileLists(WP_CONTENT_DIR); } $this->setDirFilters(); $this->setFileFilters(); $this->setTreeFilters(); } $this->FilterDirsAll = array_merge($this->FilterDirsAll, $this->FilterInfo->Dirs->Unreadable); $this->FilterFilesAll = array_merge($this->FilterFilesAll, $this->FilterInfo->Files->Unreadable); sort($this->FilterDirsAll); return $this; } /** * Save any property of this class through reflection * * @param $property A valid public property in this class * @param $value The value for the new dynamic property * * @return bool Returns true if the value has changed. */ public function saveActiveItem($package, $property, $value) { $package = DUP_Package::getActive(); $reflectionClass = new ReflectionClass($package->Archive); $reflectionClass->getProperty($property)->setValue($package->Archive, $value); return update_option(DUP_Package::OPT_ACTIVE, $package); } /** * Properly creates the directory filter list that is used for filtering directories * * @param string $dirs A semi-colon list of dir paths * /path1_/path/;/path1_/path2/; * * @returns string A cleaned up list of directory filters * @return string */ public function parseDirectoryFilter($dirs = "") { $filters = ""; $dir_array = array_unique(explode(";", $dirs)); $clean_array = array(); foreach ($dir_array as $val) { $val = DupLiteSnapLibIOU::safePathUntrailingslashit(DupLiteSnapLibUtil::sanitize_non_stamp_chars_newline_and_trim($val)); if (strlen($val) >= 2 && is_dir($val)) { $clean_array[] = $val; } } if (count($clean_array)) { $clean_array = array_unique($clean_array); sort($clean_array); $filters = implode(';', $clean_array).';'; } return $filters; } /** * Properly creates the file filter list that is used for filtering files * * @param string $files A semi-colon list of file paths * /path1_/path/file1.ext;/path1_/path2/file2.ext; * * @returns string A cleaned up list of file filters * @return string */ public function parseFileFilter($files = "") { $filters = ""; $file_array = array_unique(explode(";", $files)); $clean_array = array(); foreach ($file_array as $val) { $val = DupLiteSnapLibIOU::safePathUntrailingslashit(DupLiteSnapLibUtil::sanitize_non_stamp_chars_newline_and_trim($val)); if (strlen($val) >= 2 && file_exists($val)) { $clean_array[] = $val; } } if (count($clean_array)) { $clean_array = array_unique($clean_array); sort($clean_array); $filters = implode(';', $clean_array).';'; } return $filters; } /** * Properly creates the extension filter list that is used for filtering extensions * * @param string $dirs A semi-colon list of dir paths * .jpg;.zip;.gif; * * @returns string A cleaned up list of extension filters */ public function parseExtensionFilter($extensions = "") { $filter_exts = ""; if (strlen($extensions) >= 1 && $extensions != ";") { $filter_exts = str_replace(array(' ', '.'), '', $extensions); $filter_exts = str_replace(",", ";", $filter_exts); $filter_exts = DUP_Util::appendOnce($extensions, ";"); } return $filter_exts; } /** * Creates the filter info setup data used for filtering the archive * * @return null */ private function createFilterInfo() { //FILTER: INSTANCE ITEMS //Add the items generated at create time if ($this->FilterOn) { $this->FilterInfo->Dirs->Instance = array_map('DUP_Util::safePath', explode(";", $this->FilterDirs, -1)); $this->FilterInfo->Files->Instance = array_map('DUP_Util::safePath', explode(";", $this->FilterFiles, -1)); $this->FilterInfo->Exts->Instance = explode(";", $this->FilterExts, -1); } //FILTER: CORE ITMES //Filters Duplicator free packages & All pro local directories $wp_root = duplicator_get_abs_path(); $upload_dir = wp_upload_dir(); $upload_dir = isset($upload_dir['basedir']) ? basename($upload_dir['basedir']) : 'uploads'; $wp_content = str_replace("\\", "/", WP_CONTENT_DIR); $wp_content_upload = "{$wp_content}/{$upload_dir}"; $this->FilterInfo->Dirs->Core = array( //WP-ROOT DUP_Settings::getSsdirPathLegacy(), DUP_Settings::getSsdirPathWpCont(), $wp_root.'/.opcache', //WP-CONTENT $wp_content.'/backups-dup-pro', $wp_content.'/ai1wm-backups', $wp_content.'/backupwordpress', $wp_content.'/content/cache', $wp_content.'/contents/cache', $wp_content.'/infinitewp/backups', $wp_content.'/managewp/backups', $wp_content.'/old-cache', $wp_content.'/plugins/all-in-one-wp-migration/storage', $wp_content.'/updraft', $wp_content.'/wishlist-backup', $wp_content.'/wfcache', $wp_content.'/bps-backup', // BulletProof Security backup folder $wp_content.'/cache', //WP-CONTENT-UPLOADS $wp_content_upload.'/aiowps_backups', $wp_content_upload.'/backupbuddy_temp', $wp_content_upload.'/backupbuddy_backups', $wp_content_upload.'/ithemes-security/backups', $wp_content_upload.'/mainwp/backup', $wp_content_upload.'/pb_backupbuddy', $wp_content_upload.'/snapshots', $wp_content_upload.'/sucuri', $wp_content_upload.'/wp-clone', $wp_content_upload.'/wp_all_backup', $wp_content_upload.'/wpbackitup_backups' ); if (class_exists('BackWPup')) { $upload_dir = wp_upload_dir(null, false, true); $this->FilterInfo->Dirs->Core[] = trailingslashit(str_replace( '\\', '/', $upload_dir['basedir'])).'backwpup-'.BackWPup::get_plugin_data('hash').'-backups/'; $backwpup_cfg_logfolder = get_site_option('backwpup_cfg_logfolder'); if (false !== $backwpup_cfg_logfolder) { $this->FilterInfo->Dirs->Core[] = $wp_content.'/'.$backwpup_cfg_logfolder; } } $duplicator_global_file_filters_on = apply_filters('duplicator_global_file_filters_on', $GLOBALS['DUPLICATOR_GLOBAL_FILE_FILTERS_ON']); if ($GLOBALS['DUPLICATOR_GLOBAL_FILE_FILTERS_ON']) { $duplicator_global_file_filters = apply_filters('duplicator_global_file_filters', $GLOBALS['DUPLICATOR_GLOBAL_FILE_FILTERS']); $this->FilterInfo->Files->Global = $duplicator_global_file_filters; } // Prevent adding double wp-content dir conflicts if ($this->isOuterWPContentDir()) { $default_wp_content_dir_path = DUP_Util::safePath(ABSPATH.'wp-content'); if (file_exists($default_wp_content_dir_path)) { if (is_dir($default_wp_content_dir_path)) { $this->FilterInfo->Dirs->Core[] = $default_wp_content_dir_path; } else { $this->FilterInfo->Files->Core[] = $default_wp_content_dir_path; } } } $this->FilterDirsAll = array_merge($this->FilterInfo->Dirs->Instance, $this->FilterInfo->Dirs->Core); $this->FilterExtsAll = array_merge($this->FilterInfo->Exts->Instance, $this->FilterInfo->Exts->Core); $this->FilterFilesAll = array_merge($this->FilterInfo->Files->Instance, $this->FilterInfo->Files->Global); $abs_path = duplicator_get_abs_path(); $this->FilterFilesAll[] = $abs_path.'/.htaccess'; $this->FilterFilesAll[] = $abs_path.'/web.config'; $this->FilterFilesAll[] = $abs_path.'/wp-config.php'; $this->tmpFilterDirsAll = $this->FilterDirsAll; //PHP 5 on windows decode patch if (!DUP_Util::$PHP7_plus && DUP_Util::isWindows()) { foreach ($this->tmpFilterDirsAll as $key => $value) { if (preg_match('/[^\x20-\x7f]/', $value)) { $this->tmpFilterDirsAll[$key] = utf8_decode($value); } } } } /** * Get All Directories then filter * * @return null */ private function setDirFilters() { $this->FilterInfo->Dirs->Warning = array(); $this->FilterInfo->Dirs->Unreadable = array(); $this->FilterInfo->Dirs->AddonSites = array(); $skip_archive_scan = DUP_Settings::Get('skip_archive_scan'); $utf8_key_list = array(); $unset_key_list = array(); //Filter directories invalid test checks for: // - characters over 250 // - invlaid characters // - empty string // - directories ending with period (Windows incompatable) foreach ($this->Dirs as $key => $val) { $name = basename($val); //Dir is not readble remove flag for removal if (!is_readable($this->Dirs[$key])) { $unset_key_list[] = $key; $this->FilterInfo->Dirs->Unreadable[] = DUP_Encoding::toUTF8($val); } if (!$skip_archive_scan) { //Locate invalid directories and warn $invalid_test = (defined('PHP_MAXPATHLEN') && (strlen($val) > PHP_MAXPATHLEN)) || preg_match('/(\/|\*|\?|\>|\<|\:|\\|\|)/', $name) || trim($name) == '' || (strrpos($name, '.') == strlen($name) - 1 && substr($name, -1) == '.') || preg_match('/[^\x20-\x7f]/', $name); if ($invalid_test) { $utf8_key_list[] = $key; $this->FilterInfo->Dirs->Warning[] = DUP_Encoding::toUTF8($val); } } //Check for other WordPress installs if ($name === 'wp-admin') { $parent_dir = realpath(dirname($this->Dirs[$key])); if ($parent_dir != realpath(duplicator_get_abs_path())) { if (file_exists("$parent_dir/wp-includes")) { if (file_exists("$parent_dir/wp-config.php")) { // Ensure we aren't adding any critical directories $parent_name = basename($parent_dir); if (($parent_name != 'wp-includes') && ($parent_name != 'wp-content') && ($parent_name != 'wp-admin')) { $this->FilterInfo->Dirs->AddonSites[] = str_replace("\\", '/', $parent_dir); } } } } } } //Try to repair utf8 paths foreach ($utf8_key_list as $key) { $this->Dirs[$key] = DUP_Encoding::toUTF8($this->Dirs[$key]); } //Remove unreadable items outside of main loop for performance if (count($unset_key_list)) { foreach ($unset_key_list as $key) { unset($this->Dirs[$key]); } $this->Dirs = array_values($this->Dirs); } } /** * Get all files and filter out error prone subsets * * @return null */ private function setFileFilters() { //Init for each call to prevent concatination from stored entity objects $this->Size = 0; $this->FilterInfo->Files->Size = array(); $this->FilterInfo->Files->Warning = array(); $this->FilterInfo->Files->Unreadable = array(); $skip_archive_scan = DUP_Settings::Get('skip_archive_scan'); $utf8_key_list = array(); $unset_key_list = array(); $wpconfig_filepath = $this->getWPConfigFilePath(); if (!is_readable($wpconfig_filepath)) { $this->FilterInfo->Files->Unreadable[] = $wpconfig_filepath; } foreach ($this->Files as $key => $filePath) { $fileName = basename($filePath); if (!is_readable($filePath)) { $unset_key_list[] = $key; $this->FilterInfo->Files->Unreadable[] = $filePath; continue; } $fileSize = @filesize($filePath); $fileSize = empty($fileSize) ? 0 : $fileSize; $this->Size += $fileSize; if (!$skip_archive_scan) { $invalid_test = (defined('PHP_MAXPATHLEN') && (strlen($filePath) > PHP_MAXPATHLEN)) || preg_match('/(\/|\*|\?|\>|\<|\:|\\|\|)/', $fileName) || trim($fileName) == "" || preg_match('/[^\x20-\x7f]/', $fileName); if ($invalid_test) { $utf8_key_list[] = $key; $filePath = DUP_Encoding::toUTF8($filePath); $fileName = basename($filePath); $this->FilterInfo->Files->Warning[] = array( 'name' => $fileName, 'dir' => pathinfo($filePath, PATHINFO_DIRNAME), 'path' => $filePath); } if ($fileSize > DUPLICATOR_SCAN_WARNFILESIZE) { //$ext = pathinfo($filePath, PATHINFO_EXTENSION); $this->FilterInfo->Files->Size[] = array( 'ubytes' => $fileSize, 'bytes' => DUP_Util::byteSize($fileSize, 0), 'name' => $fileName, 'dir' => pathinfo($filePath, PATHINFO_DIRNAME), 'path' => $filePath); } } } //Try to repair utf8 paths foreach ($utf8_key_list as $key) { $this->Files[$key] = DUP_Encoding::toUTF8($this->Files[$key]); } //Remove unreadable items outside of main loop for performance if (count($unset_key_list)) { foreach ($unset_key_list as $key) { unset($this->Files[$key]); } $this->Files = array_values($this->Files); } } /** * Recursive function to get all directories in a wp install * * @notes: * Older PHP logic which is more stable on older version of PHP * NOTE RecursiveIteratorIterator is problematic on some systems issues include: * - error 'too many files open' for recursion * - $file->getExtension() is not reliable as it silently fails at least in php 5.2.17 * - issues with when a file has a permission such as 705 and trying to get info (had to fallback to pathinfo) * - basic conclusion wait on the SPL libs until after php 5.4 is a requirments * - tight recursive loop use caution for speed * * @return array Returns an array of directories to include in the archive */ private function getFileLists($path) { $handle = @opendir($path); if ($handle) { while (($file = readdir($handle)) !== false) { if ($file == '.' || $file == '..') { continue; } $fullPath = str_replace("\\", '/', "{$path}/{$file}"); // @todo: Don't leave it like this. Convert into an option on the package to not follow symbolic links // if (is_dir($fullPath) && (is_link($fullPath) == false)) if (is_dir($fullPath)) { $add = true; if (!is_link($fullPath)){ foreach ($this->tmpFilterDirsAll as $key => $val) { $trimmedFilterDir = rtrim($val, '/'); if ($fullPath == $trimmedFilterDir || strpos($fullPath, $trimmedFilterDir . '/') !== false) { $add = false; unset($this->tmpFilterDirsAll[$key]); break; } } } else{ //Convert relative path of link to absolute path chdir($fullPath); $link_path = str_replace("\\", '/', realpath(readlink($fullPath))); chdir(dirname(__FILE__)); $link_pos = strpos($fullPath,$link_path); if($link_pos === 0 && (strlen($link_path) < strlen($fullPath))){ $add = false; $this->RecursiveLinks[] = $fullPath; $this->FilterDirsAll[] = $fullPath; } else { foreach ($this->tmpFilterDirsAll as $key => $val) { $trimmedFilterDir = rtrim($val, '/'); if ($fullPath == $trimmedFilterDir || strpos($fullPath, $trimmedFilterDir . '/') !== false) { $add = false; unset($this->tmpFilterDirsAll[$key]); break; } } } } if ($add) { $this->getFileLists($fullPath); $this->Dirs[] = $fullPath; } } else { if ( ! (in_array(pathinfo($file, PATHINFO_EXTENSION), $this->FilterExtsAll) || in_array($fullPath, $this->FilterFilesAll) || in_array($file, $this->FilterFilesAll))) { $this->Files[] = $fullPath; } } } closedir($handle); } return $this->Dirs; } /** * Builds a tree for both file size warnings and name check warnings * The trees are used to apply filters from the scan screen * * @return null */ private function setTreeFilters() { //------------------------- //SIZE TREE //BUILD: File Size tree $dir_group = DUP_Util::array_group_by($this->FilterInfo->Files->Size, "dir"); ksort($dir_group); foreach ($dir_group as $dir => $files) { $sum = 0; foreach ($files as $key => $value) { $sum += $value['ubytes']; } //Locate core paths, wp-admin, wp-includes, etc. $iscore = 0; foreach ($this->wpCorePaths as $core_dir) { if (strpos(DUP_Util::safePath($dir), DUP_Util::safePath($core_dir)) !== false) { $iscore = 1; break; } } // Check root and content exact dir if (!$iscore) { if (in_array($dir, $this->wpCoreExactPaths)) { $iscore = 1; } } $this->FilterInfo->TreeSize[] = array( 'size' => DUP_Util::byteSize($sum, 0), 'dir' => $dir, 'sdir' => str_replace(duplicator_get_abs_path(), '/', $dir), 'iscore' => $iscore, 'files' => $files ); } //------------------------- //NAME TREE //BUILD: Warning tree for file names $dir_group = DUP_Util::array_group_by($this->FilterInfo->Files->Warning, "dir"); ksort($dir_group); foreach ($dir_group as $dir => $files) { //Locate core paths, wp-admin, wp-includes, etc. $iscore = 0; foreach ($this->wpCorePaths as $core_dir) { if (strpos($dir, $core_dir) !== false) { $iscore = 1; break; } } // Check root and content exact dir if (!$iscore) { if (in_array($dir, $this->wpCoreExactPaths)) { $iscore = 1; } } $this->FilterInfo->TreeWarning[] = array( 'dir' => $dir, 'sdir' => str_replace(duplicator_get_abs_path(), '/', $dir), 'iscore' => $iscore, 'count' => count($files), 'files' => $files); } //BUILD: Warning tree for dir names foreach ($this->FilterInfo->Dirs->Warning as $dir) { $add_dir = true; foreach ($this->FilterInfo->TreeWarning as $key => $value) { if ($value['dir'] == $dir) { $add_dir = false; break; } } if ($add_dir) { //Locate core paths, wp-admin, wp-includes, etc. $iscore = 0; foreach ($this->wpCorePaths as $core_dir) { if (strpos(DUP_Util::safePath($dir), DUP_Util::safePath($core_dir)) !== false) { $iscore = 1; break; } } // Check root and content exact dir if (!$iscore) { if (in_array($dir, $this->wpCoreExactPaths)) { $iscore = 1; } } $this->FilterInfo->TreeWarning[] = array( 'dir' => $dir, 'sdir' => str_replace(duplicator_get_abs_path(), '/', $dir), 'iscore' => $iscore, 'count' => 0); } } function _sortDir($a, $b) { return strcmp($a["dir"], $b["dir"]); } usort($this->FilterInfo->TreeWarning, "_sortDir"); } public function getWPConfigFilePath() { $wpconfig_filepath = ''; $abs_path = duplicator_get_abs_path(); if (file_exists($abs_path.'/wp-config.php')) { $wpconfig_filepath = $abs_path.'/wp-config.php'; } elseif (@file_exists(dirname($abs_path).'/wp-config.php') && !@file_exists(dirname($abs_path).'/wp-settings.php')) { $wpconfig_filepath = dirname($abs_path).'/wp-config.php'; } return $wpconfig_filepath; } public function isOuterWPContentDir() { if (!isset($this->isOuterWPContentDir)) { $abspath_normalize = wp_normalize_path(ABSPATH); $wp_content_dir_normalize = wp_normalize_path(WP_CONTENT_DIR); if (0 !== strpos($wp_content_dir_normalize, $abspath_normalize)) { $this->isOuterWPContentDir = true; } else { $this->isOuterWPContentDir = false; } } return $this->isOuterWPContentDir; } public function wpContentDirNormalizePath() { if (!isset($this->wpContentDirNormalizePath)) { $this->wpContentDirNormalizePath = trailingslashit(wp_normalize_path(WP_CONTENT_DIR)); } return $this->wpContentDirNormalizePath; } public function getUrl() { return DUP_Settings::getSsdirUrl()."/".$this->File; } public function getLocalDirPath($dir, $basePath = '') { $isOuterWPContentDir = $this->isOuterWPContentDir(); $wpContentDirNormalizePath = $this->wpContentDirNormalizePath(); $compressDir = rtrim(wp_normalize_path(DUP_Util::safePath($this->PackDir)), '/'); $dir = trailingslashit(wp_normalize_path($dir)); if ($isOuterWPContentDir && 0 === strpos($dir, $wpContentDirNormalizePath)) { $newWPContentDirPath = empty($basePath) ? 'wp-content/' : $basePath.'wp-content/'; $emptyDir = ltrim(str_replace($wpContentDirNormalizePath, $newWPContentDirPath, $dir), '/'); } else { $emptyDir = ltrim($basePath.preg_replace('/^'.preg_quote($compressDir, '/').'(.*)/m', '$1', $dir), '/'); } return $emptyDir; } public function getLocalFilePath($file, $basePath = '') { $isOuterWPContentDir = $this->isOuterWPContentDir(); $wpContentDirNormalizePath = $this->wpContentDirNormalizePath(); $compressDir = rtrim(wp_normalize_path(DUP_Util::safePath($this->PackDir)), '/'); $file = wp_normalize_path($file); if ($isOuterWPContentDir && 0 === strpos($file, $wpContentDirNormalizePath)) { $newWPContentDirPath = empty($basePath) ? 'wp-content/' : $basePath.'wp-content/'; $localFileName = ltrim(str_replace($wpContentDirNormalizePath, $newWPContentDirPath, $file), '/'); } else { $localFileName = ltrim($basePath.preg_replace('/^'.preg_quote($compressDir, '/').'(.*)/m', '$1', $file), '/'); } return $localFileName; } } package/class.pack.database.php 0000644 00000074666 15133151516 0012461 0 ustar 00 <?php defined('ABSPATH') || defined('DUPXABSPATH') || exit; // Exit if accessed directly if (!defined('DUPLICATOR_VERSION')) exit; /** * Class for gathering system information about a database * * Standard: PSR-2 * @link http://www.php-fig.org/psr/psr-2 * */ class DUP_DatabaseInfo { /** * The SQL file was built with mysqldump or PHP */ public $buildMode; /** * A unique list of all the collation table types used in the database */ public $collationList; /** * Does any filtered table have an upper case character in it */ public $isTablesUpperCase; /** * Does the database name have any filtered characters in it */ public $isNameUpperCase; /** * The real name of the database */ public $name; /** * The full count of all tables in the database */ public $tablesBaseCount; /** * The count of tables after the tables filter has been applied */ public $tablesFinalCount; /** * The number of rows from all filtered tables in the database */ public $tablesRowCount; /** * The estimated data size on disk from all filtered tables in the database */ public $tablesSizeOnDisk; /** * Gets the server variable lower_case_table_names * * 0 store=lowercase; compare=sensitive (works only on case sensitive file systems ) * 1 store=lowercase; compare=insensitive * 2 store=exact; compare=insensitive (works only on case INsensitive file systems ) * default is 0/Linux ; 1/Windows */ public $varLowerCaseTables; /** * The simple numeric version number of the database server * @exmaple: 5.5 */ public $version; /** * The full text version number of the database server * @exmaple: 10.2 mariadb.org binary distribution */ public $versionComment; /** * table wise row counts array, Key as table name and value as row count * table name => row count */ public $tableWiseRowCounts; /** * @var array List of triggers included in the database */ public $triggerList = array(); /** * Integer field file structure of table, table name as key */ private $intFieldsStruct = array(); /** * $currentIndex => processedSchemaSize */ private $indexProcessedSchemaSize = array(); //CONSTRUCTOR function __construct() { $this->collationList = array(); $this->tableWiseRowCounts = array(); } public function addTriggers() { global $wpdb; if (!is_array($triggers = $wpdb->get_results("SHOW TRIGGERS", ARRAY_A))) { return; } foreach ($triggers as $trigger) { $name = $trigger["Trigger"]; $create = $wpdb->get_row("SHOW CREATE TRIGGER `{$name}`", ARRAY_N); $this->triggerList[$name] = array( "create" => "DELIMITER ;;\n".$create[2].";;\nDELIMITER ;" ); } } } class DUP_Database { //PUBLIC public $Type = 'MySQL'; public $Size; public $File; public $Path; public $FilterTables; public $FilterOn; public $Name; public $Compatible; public $Comments; /** * * @var DUP_DatabaseInfo */ public $info = null; //PROTECTED protected $Package; //PRIVATE private $tempDbPath; private $EOFMarker; private $networkFlush; /** * Init this object */ function __construct($package) { $this->Package = $package; $this->EOFMarker = ""; $package_zip_flush = DUP_Settings::Get('package_zip_flush'); $this->networkFlush = empty($package_zip_flush) ? false : $package_zip_flush; $this->info = new DUP_DatabaseInfo(); $this->info->varLowerCaseTables = DUP_Util::isWindows() ? 1 : 0; } /** * Build the database script * * @param DUP_Package $package A reference to the package that this database object belongs in * * @return null */ public function build($package, $errorBehavior = Dup_ErrorBehavior::ThrowException) { try { $this->Package = $package; do_action('duplicator_lite_build_database_before_start', $package); $time_start = DUP_Util::getMicrotime(); $this->Package->setStatus(DUP_PackageStatus::DBSTART); $this->tempDbPath = DUP_Settings::getSsdirTmpPath()."/{$this->File}"; $package_mysqldump = DUP_Settings::Get('package_mysqldump'); $package_phpdump_qrylimit = DUP_Settings::Get('package_phpdump_qrylimit'); $mysqlDumpPath = DUP_DB::getMySqlDumpPath(); $mode = DUP_DB::getBuildMode(); $reserved_db_filepath = duplicator_get_abs_path().'/database.sql'; $log = "\n********************************************************************************\n"; $log .= "DATABASE:\n"; $log .= "********************************************************************************\n"; $log .= "BUILD MODE: {$mode}"; $log .= ($mode == 'PHP') ? "(query limit - {$package_phpdump_qrylimit})\n" : "\n"; $log .= "MYSQLTIMEOUT: ".DUPLICATOR_DB_MAX_TIME."\n"; $log .= "MYSQLDUMP: "; $log .= ($mysqlDumpPath) ? "Is Supported" : "Not Supported"; DUP_Log::Info($log); $log = null; do_action('duplicator_lite_build_database_start', $package); switch ($mode) { case 'MYSQLDUMP': $this->mysqlDump($mysqlDumpPath); break; case 'PHP' : $this->phpDump($package); break; } DUP_Log::Info("SQL CREATED: {$this->File}"); $time_end = DUP_Util::getMicrotime(); $time_sum = DUP_Util::elapsedTime($time_end, $time_start); //File below 10k considered incomplete $sql_file_size = is_file($this->tempDbPath) ? @filesize($this->tempDbPath) : 0; DUP_Log::Info("SQL FILE SIZE: ".DUP_Util::byteSize($sql_file_size)." ({$sql_file_size})"); if ($sql_file_size < 1350) { $error_message = "SQL file size too low."; $package->BuildProgress->set_failed($error_message); $package->Status = DUP_PackageStatus::ERROR; $package->Update(); DUP_Log::error($error_message, "File does not look complete. Check permission on file and parent directory at [{$this->tempDbPath}]", $errorBehavior); do_action('duplicator_lite_build_database_fail', $package); } else { do_action('duplicator_lite_build_database_completed', $package); } DUP_Log::Info("SQL FILE TIME: ".date("Y-m-d H:i:s")); DUP_Log::Info("SQL RUNTIME: {$time_sum}"); $this->Size = is_file($this->tempDbPath) ? @filesize($this->tempDbPath) : 0; $this->Package->setStatus(DUP_PackageStatus::DBDONE); } catch (Exception $e) { do_action('duplicator_lite_build_database_fail', $package); DUP_Log::error("Runtime error in DUP_Database::Build. ".$e->getMessage(), "Exception: {$e}", $errorBehavior); } } /** * Get the database meta-data such as tables as all there details * * @return array Returns an array full of meta-data about the database */ public function getScannerData() { global $wpdb; $filterTables = isset($this->FilterTables) ? explode(',', $this->FilterTables) : array(); $tblBaseCount = 0; $tblCount = 0; $tables = $wpdb->get_results("SHOW TABLE STATUS", ARRAY_A); $info = array(); $info['Status']['Success'] = is_null($tables) ? false : true; //DB_Case for the database name is never checked on $info['Status']['DB_Case'] = 'Good'; $info['Status']['DB_Rows'] = 'Good'; $info['Status']['DB_Size'] = 'Good'; $info['Status']['TBL_Case'] = 'Good'; $info['Status']['TBL_Rows'] = 'Good'; $info['Status']['TBL_Size'] = 'Good'; $info['Size'] = 0; $info['Rows'] = 0; $info['TableCount'] = 0; $info['TableList'] = array(); $tblCaseFound = 0; $tblRowsFound = 0; $tblSizeFound = 0; //Grab Table Stats $filteredTables = array(); foreach ($tables as $table) { $tblBaseCount++; $name = $table["Name"]; if ($this->FilterOn && is_array($filterTables)) { if (in_array($name, $filterTables)) { continue; } } $size = ($table["Data_length"] + $table["Index_length"]); $rows = empty($table["Rows"]) ? '0' : $table["Rows"]; $info['Size'] += $size; $info['Rows'] += ($table["Rows"]); $info['TableList'][$name]['Case'] = preg_match('/[A-Z]/', $name) ? 1 : 0; $info['TableList'][$name]['Rows'] = number_format($rows); $info['TableList'][$name]['Size'] = DUP_Util::byteSize($size); $info['TableList'][$name]['USize'] = $size; $filteredTables[] = $name; $tblCount++; //Table Uppercase if ($info['TableList'][$name]['Case']) { if (!$tblCaseFound) { $tblCaseFound = 1; } } //Table Row Count if ($rows > DUPLICATOR_SCAN_DB_TBL_ROWS) { if (!$tblRowsFound) { $tblRowsFound = 1; } } //Table Size if ($size > DUPLICATOR_SCAN_DB_TBL_SIZE) { if (!$tblSizeFound) { $tblSizeFound = 1; } } } $this->setInfoObj($filteredTables); $this->info->addTriggers(); $info['Status']['DB_Case'] = preg_match('/[A-Z]/', $wpdb->dbname) ? 'Warn' : 'Good'; $info['Status']['DB_Rows'] = ($info['Rows'] > DUPLICATOR_SCAN_DB_ALL_ROWS) ? 'Warn' : 'Good'; $info['Status']['DB_Size'] = ($info['Size'] > DUPLICATOR_SCAN_DB_ALL_SIZE) ? 'Warn' : 'Good'; $info['Status']['TBL_Case'] = ($tblCaseFound) ? 'Warn' : 'Good'; $info['Status']['TBL_Rows'] = ($tblRowsFound) ? 'Warn' : 'Good'; $info['Status']['TBL_Size'] = ($tblSizeFound) ? 'Warn' : 'Good'; $info['Status']['Triggers'] = count($this->info->triggerList) > 0 ? 'Warn' : 'Good'; $info['RawSize'] = $info['Size']; $info['Size'] = DUP_Util::byteSize($info['Size']) or "unknown"; $info['Rows'] = number_format($info['Rows']) or "unknown"; $info['TableList'] = $info['TableList'] or "unknown"; $info['TableCount'] = $tblCount; $this->info->isTablesUpperCase = $tblCaseFound; $this->info->tablesBaseCount = $tblBaseCount; $this->info->tablesFinalCount = $tblCount; $this->info->tablesRowCount = $info['Rows']; $this->info->tablesSizeOnDisk = $info['Size']; return $info; } /** * @param array &$filteredTables Filtered names of tables to include in collation search. * Parameter does not change in the function, is passed by reference only to avoid copying. * * @return void */ public function setInfoObj(&$filteredTables) { global $wpdb; $this->info->buildMode = DUP_DB::getBuildMode(); $this->info->version = DUP_DB::getVersion(); $this->info->versionComment = DUP_DB::getVariable('version_comment'); $this->info->varLowerCaseTables = DUP_DB::getVariable('lower_case_table_names'); $this->info->name = $wpdb->dbname; $this->info->isNameUpperCase = preg_match('/[A-Z]/', $wpdb->dbname) ? 1 : 0; $this->info->collationList = DUP_DB::getTableCollationList($filteredTables); } /** * Unset tableWiseRowCounts table key for which row count is unstable * * @param object $package The reference to the current package being built * * @return void */ public function validateTableWiseRowCounts() { foreach ($this->Package->Database->info->tableWiseRowCounts as $rewriteTableAs => $rowCount) { $newRowCount = $GLOBALS['wpdb']->get_var("SELECT Count(*) FROM `{$rewriteTableAs}`"); if ($rowCount != $newRowCount) { unset($this->Package->Database->info->tableWiseRowCounts[$rewriteTableAs]); } } } /** * Build the database script using mysqldump * * @return bool Returns true if the sql script was successfully created */ private function mysqlDump($exePath) { global $wpdb; require_once (DUPLICATOR_PLUGIN_PATH.'classes/utilities/class.u.shell.php'); $host = explode(':', DB_HOST); $host = reset($host); $port = strpos(DB_HOST, ':') ? end(explode(':', DB_HOST)) : ''; $name = DB_NAME; $mysqlcompat_on = isset($this->Compatible) && strlen($this->Compatible); //Build command $cmd = escapeshellarg($exePath); $cmd .= ' --no-create-db'; $cmd .= ' --single-transaction'; $cmd .= ' --hex-blob'; $cmd .= ' --skip-add-drop-table'; $cmd .= ' --routines'; $cmd .= ' --quote-names'; $cmd .= ' --skip-comments'; $cmd .= ' --skip-set-charset'; $cmd .= ' --skip-triggers'; $cmd .= ' --allow-keywords'; $cmd .= ' --no-tablespaces'; //Compatibility mode if ($mysqlcompat_on) { DUP_Log::Info("COMPATIBLE: [{$this->Compatible}]"); $cmd .= " --compatible={$this->Compatible}"; } //Filter tables $res = $wpdb->get_results('SHOW FULL TABLES', ARRAY_N); $tables = array(); $baseTables = array(); foreach ($res as $row) { if (DUP_Util::isTableExists($row[0])) { $tables[] = $row[0]; if ('BASE TABLE' == $row[1]) { $baseTables[] = $row[0]; } } } $filterTables = isset($this->FilterTables) ? explode(',', $this->FilterTables) : null; $tblAllCount = count($tables); foreach ($tables as $table) { if (in_array($table, $baseTables)) { $row_count = $GLOBALS['wpdb']->get_var("SELECT Count(*) FROM `{$table}`"); $rewrite_table_as = $this->rewriteTableNameAs($table); $this->Package->Database->info->tableWiseRowCounts[$rewrite_table_as] = $row_count; } } //$tblFilterOn = ($this->FilterOn) ? 'ON' : 'OFF'; if (is_array($filterTables) && $this->FilterOn) { foreach ($tables as $key => $val) { if (in_array($tables[$key], $filterTables)) { $cmd .= " --ignore-table={$name}.{$tables[$key]} "; unset($tables[$key]); } } } $cmd .= ' -u '.escapeshellarg(DB_USER); $cmd .= (DB_PASSWORD) ? ' -p'.DUP_Shell_U::escapeshellargWindowsSupport(DB_PASSWORD) : ''; $cmd .= ' -h '.escapeshellarg($host); $cmd .= (!empty($port) && is_numeric($port) ) ? ' -P '.$port : ''; $isPopenEnabled = DUP_Shell_U::isPopenEnabled(); if (!$isPopenEnabled) { $cmd .= ' -r '.escapeshellarg($this->tempDbPath); } $cmd .= ' '.escapeshellarg(DB_NAME); $cmd .= ' 2>&1'; if ($isPopenEnabled) { $needToRewrite = false; foreach ($tables as $tableName) { $rewriteTableAs = $this->rewriteTableNameAs($tableName); if ($tableName != $rewriteTableAs) { $needToRewrite = true; break; } } if ($needToRewrite) { $findReplaceTableNames = array(); // orignal table name => rewrite table name foreach ($tables as $tableName) { $rewriteTableAs = $this->rewriteTableNameAs($tableName); if ($tableName != $rewriteTableAs) { $findReplaceTableNames[$tableName] = $rewriteTableAs; } } } $firstLine = ''; DUP_LOG::trace("Executing mysql dump command by popen: $cmd"); $handle = popen($cmd, "r"); if ($handle) { $sql_header = "/* DUPLICATOR-LITE (MYSQL-DUMP BUILD MODE) MYSQL SCRIPT CREATED ON : ".@date("Y-m-d H:i:s")." */\n\n"; file_put_contents($this->tempDbPath, $sql_header, FILE_APPEND); while (!feof($handle)) { $line = fgets($handle); //get ony one line if ($line) { if (empty($firstLine)) { $firstLine = $line; if (false !== stripos($line, 'Using a password on the command line interface can be insecure')) continue; } if ($needToRewrite) { $replaceCount = 1; if (preg_match('/CREATE TABLE `(.*?)`/', $line, $matches)) { $tableName = $matches[1]; if (isset($findReplaceTableNames[$tableName])) { $rewriteTableAs = $findReplaceTableNames[$tableName]; $line = str_replace('CREATE TABLE `'.$tableName.'`', 'CREATE TABLE `'.$rewriteTableAs.'`', $line, $replaceCount); } } elseif (preg_match('/INSERT INTO `(.*?)`/', $line, $matches)) { $tableName = $matches[1]; if (isset($findReplaceTableNames[$tableName])) { $rewriteTableAs = $findReplaceTableNames[$tableName]; $line = str_replace('INSERT INTO `'.$tableName.'`', 'INSERT INTO `'.$rewriteTableAs.'`', $line, $replaceCount); } } elseif (preg_match('/LOCK TABLES `(.*?)`/', $line, $matches)) { $tableName = $matches[1]; if (isset($findReplaceTableNames[$tableName])) { $rewriteTableAs = $findReplaceTableNames[$tableName]; $line = str_replace('LOCK TABLES `'.$tableName.'`', 'LOCK TABLES `'.$rewriteTableAs.'`', $line, $replaceCount); } } } file_put_contents($this->tempDbPath, $line, FILE_APPEND); $output = "Ran from {$exePath}"; } } $mysqlResult = pclose($handle); } else { $output = ''; } // Password bug > 5.6 (@see http://bugs.mysql.com/bug.php?id=66546) if (empty($output) && trim($firstLine) === 'Warning: Using a password on the command line interface can be insecure.') { $output = ''; } } else { DUP_LOG::trace("Executing mysql dump command $cmd"); exec($cmd, $output, $mysqlResult); $output = implode("\n", $output); // Password bug > 5.6 (@see http://bugs.mysql.com/bug.php?id=66546) if (trim($output) === 'Warning: Using a password on the command line interface can be insecure.') { $output = ''; } $output = (strlen($output)) ? $output : "Ran from {$exePath}"; $tblCreateCount = count($tables); $tblFilterCount = $tblAllCount - $tblCreateCount; //DEBUG //DUP_Log::Info("COMMAND: {$cmd}"); DUP_Log::Info("FILTERED: [{$this->FilterTables}]"); DUP_Log::Info("RESPONSE: {$output}"); DUP_Log::Info("TABLES: total:{$tblAllCount} | filtered:{$tblFilterCount} | create:{$tblCreateCount}"); } $sql_footer = "\n\n/* Duplicator WordPress Timestamp: ".date("Y-m-d H:i:s")."*/\n"; $sql_footer .= "/* ".DUPLICATOR_DB_EOF_MARKER." */\n"; file_put_contents($this->tempDbPath, $sql_footer, FILE_APPEND); if ($mysqlResult !== 0) { /** * -1 error command shell * mysqldump return * 0 - Success * 1 - Warning * 2 - Exception */ DUP_Log::Info('MYSQL DUMP ERROR '.print_r($mysqlResult, true)); DUP_Log::error(__('Shell mysql dump error. Change SQL Mode to the "PHP Code" in the Duplicator > Settings > Packages.', 'duplicator'), implode("\n", DupLiteSnapLibIOU::getLastLinesOfFile($this->tempDbPath, DUPLICATOR_DB_MYSQLDUMP_ERROR_CONTAINING_LINE_COUNT, DUPLICATOR_DB_MYSQLDUMP_ERROR_CHARS_IN_LINE_COUNT)), Dup_ErrorBehavior::ThrowException); return false; } return true; } /** * Build the database script using php * * @return bool Returns true if the sql script was successfully created */ private function phpDump($package) { global $wpdb; $wpdb->query("SET session wait_timeout = ".DUPLICATOR_DB_MAX_TIME); if (($handle = fopen($this->tempDbPath, 'w+')) == false) { DUP_Log::error('[PHP DUMP] ERROR Can\'t open sbStorePath "'.$this->tempDbPath.'"', Dup_ErrorBehavior::ThrowException); } $tables = $wpdb->get_col("SHOW FULL TABLES WHERE Table_Type != 'VIEW'"); $filterTables = isset($this->FilterTables) ? explode(',', $this->FilterTables) : null; $tblAllCount = count($tables); //$tblFilterOn = ($this->FilterOn) ? 'ON' : 'OFF'; $qryLimit = DUP_Settings::Get('package_phpdump_qrylimit'); if (is_array($filterTables) && $this->FilterOn) { foreach ($tables as $key => $val) { if (in_array($tables[$key], $filterTables)) { unset($tables[$key]); } } } $tblCreateCount = count($tables); $tblFilterCount = $tblAllCount - $tblCreateCount; DUP_Log::Info("TABLES: total:{$tblAllCount} | filtered:{$tblFilterCount} | create:{$tblCreateCount}"); DUP_Log::Info("FILTERED: [{$this->FilterTables}]"); //Added 'NO_AUTO_VALUE_ON_ZERO' at plugin version 1.2.12 to fix : //**ERROR** database error write 'Invalid default value for for older mysql versions $sql_header = "/* DUPLICATOR-LITE (PHP BUILD MODE) MYSQL SCRIPT CREATED ON : ".@date("Y-m-d H:i:s")." */\n\n"; $sql_header .= "/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;\n\n"; $sql_header .= "SET FOREIGN_KEY_CHECKS = 0;\n\n"; fwrite($handle, $sql_header); //BUILD CREATES: //All creates must be created before inserts do to foreign key constraints foreach ($tables as $table) { $rewrite_table_as = $this->rewriteTableNameAs($table); $create = $wpdb->get_row("SHOW CREATE TABLE `{$table}`", ARRAY_N); $count = 1; $create_table_query = str_replace($table, $rewrite_table_as, $create[1], $count); @fwrite($handle, "{$create_table_query};\n\n"); } $procedures = $wpdb->get_col("SHOW PROCEDURE STATUS WHERE `Db` = '{$wpdb->dbname}'", 1); if (count($procedures)) { foreach ($procedures as $procedure) { @fwrite($handle, "DELIMITER ;;\n"); $create = $wpdb->get_row("SHOW CREATE PROCEDURE `{$procedure}`", ARRAY_N); @fwrite($handle, "{$create[2]} ;;\n"); @fwrite($handle, "DELIMITER ;\n\n"); } } $functions = $wpdb->get_col("SHOW FUNCTION STATUS WHERE `Db` = '{$wpdb->dbname}'", 1); if (count($functions)) { foreach ($functions as $function) { @fwrite($handle, "DELIMITER ;;\n"); $create = $wpdb->get_row("SHOW CREATE FUNCTION `{$function}`", ARRAY_N); @fwrite($handle, "{$create[2]} ;;\n"); @fwrite($handle, "DELIMITER ;\n\n"); } } $views = $wpdb->get_col("SHOW FULL TABLES WHERE Table_Type = 'VIEW'"); if (count($views)) { foreach ($views as $view) { $create = $wpdb->get_row("SHOW CREATE VIEW `{$view}`", ARRAY_N); @fwrite($handle, "{$create[1]};\n\n"); } } $table_count = count($tables); $table_number = 0; //BUILD INSERTS: //Create Insert in 100 row increments to better handle memory foreach ($tables as $table) { $table_number++; if ($table_number % 2 == 0) { $this->Package->Status = DupLiteSnapLibUtil::getWorkPercent(DUP_PackageStatus::DBSTART, DUP_PackageStatus::DBDONE, $table_count, $table_number); $this->Package->update(); } $row_count = $wpdb->get_var("SELECT Count(*) FROM `{$table}`"); $rewrite_table_as = $this->rewriteTableNameAs($table); $this->Package->Database->info->tableWiseRowCounts[$rewrite_table_as] = $row_count; if ($row_count > $qryLimit) { $row_count = ceil($row_count / $qryLimit); } else if ($row_count > 0) { $row_count = 1; } if ($row_count >= 1) { fwrite($handle, "\n/* INSERT TABLE DATA: {$table} */\n"); } for ($i = 0; $i < $row_count; $i++) { $sql = ""; $limit = $i * $qryLimit; $query = "SELECT * FROM `{$table}` LIMIT {$limit}, {$qryLimit}"; $rows = $wpdb->get_results($query, ARRAY_A); $select_last_error = $wpdb->last_error; if ('' !== $select_last_error) { $fix = esc_html__('Please contact your DataBase administrator to fix the error.', 'duplicator'); $errorMessage = $select_last_error.' '.$fix.'.'; $package->BuildProgress->set_failed($errorMessage); $package->BuildProgress->failed = true; $package->failed = true; $package->Status = DUP_PackageStatus::ERROR; $package->Update(); DUP_Log::error($select_last_error, $fix, Dup_ErrorBehavior::ThrowException); return; } if (is_array($rows)) { foreach ($rows as $row) { $sql .= "INSERT INTO `{$rewrite_table_as}` VALUES("; $num_values = count($row); $num_counter = 1; foreach ($row as $value) { if (is_null($value) || !isset($value)) { ($num_values == $num_counter) ? $sql .= 'NULL' : $sql .= 'NULL, '; } else { ($num_values == $num_counter) ? $sql .= '"'.DUP_DB::escSQL($value, true).'"' : $sql .= '"'.DUP_DB::escSQL($value, true).'", '; } $num_counter++; } $sql .= ");\n"; } fwrite($handle, $sql); } } //Flush buffer if enabled if ($this->networkFlush) { DUP_Util::fcgiFlush(); } $sql = null; $rows = null; } $sql_footer = "\nSET FOREIGN_KEY_CHECKS = 1; \n\n"; $sql_footer .= "/* Duplicator WordPress Timestamp: ".date("Y-m-d H:i:s")."*/\n"; $sql_footer .= "/* ".DUPLICATOR_DB_EOF_MARKER." */\n"; fwrite($handle, $sql_footer); $wpdb->flush(); fclose($handle); } private function rewriteTableNameAs($table) { $table_prefix = $this->getTablePrefix(); if (!isset($this->sameNameTableExists)) { global $wpdb; $this->sameNameTableExists = false; $all_tables = $wpdb->get_col("SHOW FULL TABLES WHERE Table_Type != 'VIEW'"); foreach ($all_tables as $table_name) { if (strtolower($table_name) != $table_name && in_array(strtolower($table_name), $all_tables)) { $this->sameNameTableExists = true; break; } } } if (false === $this->sameNameTableExists && 0 === stripos($table, $table_prefix) && 0 !== strpos($table, $table_prefix)) { $post_fix = substr($table, strlen($table_prefix)); $rewrite_table_name = $table_prefix.$post_fix; } else { $rewrite_table_name = $table; } return $rewrite_table_name; } private function getTablePrefix() { global $wpdb; $table_prefix = (is_multisite() && !defined('MULTISITE')) ? $wpdb->base_prefix : $wpdb->get_blog_prefix(0); return $table_prefix; } public function getUrl() { return DUP_Settings::getSsdirUrl()."/".$this->File; } } package/class.pack.installer.php 0000644 00000051353 15133151516 0012676 0 ustar 00 <?php defined('ABSPATH') || defined('DUPXABSPATH') || exit; // Exit if accessed directly /* @var $global DUP_Global_Entity */ require_once(DUPLICATOR_PLUGIN_PATH.'/classes/class.archive.config.php'); require_once(DUPLICATOR_PLUGIN_PATH.'/classes/utilities/class.u.zip.php'); require_once(DUPLICATOR_PLUGIN_PATH.'/classes/utilities/class.u.multisite.php'); require_once(DUPLICATOR_PLUGIN_PATH.'/classes/class.password.php'); class DUP_Installer { const DEFAULT_INSTALLER_FILE_NAME_WITHOUT_HASH = 'installer.php'; //PUBLIC public $File; public $Size = 0; public $OptsDBHost; public $OptsDBPort; public $OptsDBName; public $OptsDBUser; public $OptsDBCharset; public $OptsDBCollation; public $OptsSecureOn = 0; public $OptsSecurePass; public $numFilesAdded = 0; public $numDirsAdded = 0; //PROTECTED protected $Package; /** * Init this object */ function __construct($package) { $this->Package = $package; } public function build($package, $error_behavior = Dup_ErrorBehavior::Quit) { DUP_Log::Info("building installer"); $this->Package = $package; $success = false; if ($this->create_enhanced_installer_files()) { $success = $this->add_extra_files($package); } else { DUP_Log::Info("error creating enhanced installer files"); } if ($success) { // No longer need to store wp-config.txt file in main storage area $temp_conf_ark_file_path = $this->getTempWPConfArkFilePath(); @unlink($temp_conf_ark_file_path); $package->BuildProgress->installer_built = true; } else { $error_message = 'Error adding installer'; $package->BuildProgress->set_failed($error_message); $package->Status = DUP_PackageStatus::ERROR; $package->Update(); DUP_Log::error($error_message, "Marking build progress as failed because couldn't add installer files", $error_behavior); //$package->BuildProgress->failed = true; //$package->setStatus(DUP_PackageStatus::ERROR); } return $success; } private function create_enhanced_installer_files() { $success = false; if ($this->create_enhanced_installer()) { $success = $this->create_archive_config_file(); } return $success; } private function create_enhanced_installer() { $success = true; $archive_filepath = DUP_Settings::getSsdirTmpPath()."/{$this->Package->Archive->File}"; $installer_filepath = apply_filters('duplicator_installer_file_path', DUP_Settings::getSsdirTmpPath()."/{$this->Package->NameHash}_installer.php"); $template_filepath = DUPLICATOR_PLUGIN_PATH.'/installer/installer.tpl'; $mini_expander_filepath = DUPLICATOR_PLUGIN_PATH.'/lib/dup_archive/classes/class.duparchive.mini.expander.php'; // Replace the @@ARCHIVE@@ token $installer_contents = file_get_contents($template_filepath); if (DUP_Settings::Get('archive_build_mode') == DUP_Archive_Build_Mode::DupArchive) { $mini_expander_string = file_get_contents($mini_expander_filepath); if ($mini_expander_string === false) { DUP_Log::error(DUP_U::__('Error reading DupArchive mini expander'), DUP_U::__('Error reading DupArchive mini expander'), Dup_ErrorBehavior::LogOnly); return false; } } else { $mini_expander_string = ''; } $search_array = array('@@ARCHIVE@@', '@@VERSION@@', '@@ARCHIVE_SIZE@@', '@@PACKAGE_HASH@@', '@@SECONDARY_PACKAGE_HASH@@', '@@DUPARCHIVE_MINI_EXPANDER@@'); $package_hash = $this->Package->getPackageHash(); $secondary_package_hash = $this->Package->getSecondaryPackageHash(); $replace_array = array($this->Package->Archive->File, DUPLICATOR_VERSION, @filesize($archive_filepath), $package_hash, $secondary_package_hash, $mini_expander_string); $installer_contents = str_replace($search_array, $replace_array, $installer_contents); if (@file_put_contents($installer_filepath, $installer_contents) === false) { DUP_Log::error(esc_html__('Error writing installer contents', 'duplicator'), esc_html__("Couldn't write to $installer_filepath", 'duplicator')); $success = false; } if ($success) { $storePath = DUP_Settings::getSsdirTmpPath()."/{$this->File}"; $this->Size = @filesize($storePath); } return $success; } /** * Create archive.txt file */ private function create_archive_config_file() { global $wpdb; $success = true; $archive_config_filepath = DUP_Settings::getSsdirTmpPath()."/{$this->Package->NameHash}_archive.txt"; $ac = new DUP_Archive_Config(); $extension = strtolower($this->Package->Archive->Format); $hasher = new DUP_PasswordHash(8, FALSE); $pass_hash = $hasher->HashPassword($this->Package->Installer->OptsSecurePass); $this->Package->Database->getScannerData(); //READ-ONLY: COMPARE VALUES $ac->created = $this->Package->Created; $ac->version_dup = DUPLICATOR_VERSION; $ac->version_wp = $this->Package->VersionWP; $ac->version_db = $this->Package->VersionDB; $ac->version_php = $this->Package->VersionPHP; $ac->version_os = $this->Package->VersionOS; $ac->dup_type = 'lite'; $ac->dbInfo = $this->Package->Database->info; //READ-ONLY: GENERAL // $ac->installer_base_name = $global->installer_base_name; $ac->installer_base_name = 'installer.php'; $ac->installer_backup_name = $this->Package->NameHash.'_installer-backup.php'; $ac->package_name = "{$this->Package->NameHash}_archive.{$extension}"; $ac->package_hash = $this->Package->getPackageHash(); $ac->package_notes = $this->Package->Notes; $ac->url_old = get_option('siteurl'); $ac->opts_delete = DupLiteSnapJsonU::wp_json_encode_pprint($GLOBALS['DUPLICATOR_OPTS_DELETE']); $ac->blogname = esc_html(get_option('blogname')); $abs_path = duplicator_get_abs_path(); $ac->wproot = $abs_path; $ac->relative_content_dir = str_replace($abs_path, '', WP_CONTENT_DIR); $ac->exportOnlyDB = $this->Package->Archive->ExportOnlyDB; $ac->installSiteOverwriteOn = DUPLICATOR_INSTALL_SITE_OVERWRITE_ON; $ac->wplogin_url = wp_login_url(); //PRE-FILLED: GENERAL $ac->secure_on = $this->Package->Installer->OptsSecureOn; $ac->secure_pass = $pass_hash; $ac->skipscan = false; $ac->dbhost = $this->Package->Installer->OptsDBHost; $ac->dbname = $this->Package->Installer->OptsDBName; $ac->dbuser = $this->Package->Installer->OptsDBUser; $ac->dbpass = ''; $ac->dbcharset = $this->Package->Installer->OptsDBCharset; $ac->dbcollation = $this->Package->Installer->OptsDBCollation; $ac->wp_tableprefix = $wpdb->base_prefix; $ac->mu_mode = DUP_MU::getMode(); $ac->is_outer_root_wp_config_file = (!file_exists($abs_path.'/wp-config.php')) ? true : false; $ac->is_outer_root_wp_content_dir = $this->Package->Archive->isOuterWPContentDir(); $json = DupLiteSnapJsonU::wp_json_encode_pprint($ac); DUP_Log::TraceObject('json', $json); if (file_put_contents($archive_config_filepath, $json) === false) { DUP_Log::error("Error writing archive config", "Couldn't write archive config at $archive_config_filepath", Dup_ErrorBehavior::LogOnly); $success = false; } return $success; } /** * Puts an installer zip file in the archive for backup purposes. */ private function add_extra_files($package) { $success = false; $installer_filepath = apply_filters('duplicator_installer_file_path', DUP_Settings::getSsdirTmpPath()."/{$this->Package->NameHash}_installer.php"); $scan_filepath = DUP_Settings::getSsdirTmpPath()."/{$this->Package->NameHash}_scan.json"; $sql_filepath = DUP_Settings::getSsdirTmpPath()."/{$this->Package->Database->File}"; $archive_filepath = DUP_Settings::getSsdirTmpPath()."/{$this->Package->Archive->File}"; $archive_config_filepath = DUP_Settings::getSsdirTmpPath()."/{$this->Package->NameHash}_archive.txt"; DUP_Log::Info("add_extra_files1"); if (file_exists($installer_filepath) == false) { DUP_Log::error("Installer $installer_filepath not present", '', Dup_ErrorBehavior::LogOnly); return false; } DUP_Log::Info("add_extra_files2"); if (file_exists($sql_filepath) == false) { DUP_Log::error("Database SQL file $sql_filepath not present", '', Dup_ErrorBehavior::LogOnly); return false; } DUP_Log::Info("add_extra_files3"); if (file_exists($archive_config_filepath) == false) { DUP_Log::error("Archive configuration file $archive_config_filepath not present", '', Dup_ErrorBehavior::LogOnly); return false; } DUP_Log::Info("add_extra_files4"); if ($package->Archive->file_count != 2) { DUP_Log::Info("Doing archive file check"); // Only way it's 2 is if the root was part of the filter in which case the archive won't be there DUP_Log::Info("add_extra_files5"); if (file_exists($archive_filepath) == false) { DUP_Log::error("$error_text. **RECOMMENDATION: $fix_text", '', Dup_ErrorBehavior::LogOnly); return false; } DUP_Log::Info("add_extra_files6"); } $wpconfig_filepath = $package->Archive->getWPConfigFilePath(); if ($package->Archive->Format == 'DAF') { DUP_Log::Info("add_extra_files7"); $success = $this->add_extra_files_using_duparchive($installer_filepath, $scan_filepath, $sql_filepath, $archive_filepath, $archive_config_filepath, $wpconfig_filepath); } else { DUP_Log::Info("add_extra_files8"); $success = $this->add_extra_files_using_ziparchive($installer_filepath, $scan_filepath, $sql_filepath, $archive_filepath, $archive_config_filepath, $wpconfig_filepath); } // No sense keeping the archive config around @unlink($archive_config_filepath); $package->Archive->Size = @filesize($archive_filepath); return $success; } private function add_extra_files_using_duparchive($installer_filepath, $scan_filepath, $sql_filepath, $archive_filepath, $archive_config_filepath, $wpconfig_filepath) { $success = false; try { DUP_Log::Info("add_extra_files_using_da1"); $htaccess_filepath = $this->getHtaccessFilePath(); $webconf_filepath = duplicator_get_abs_path().'/web.config'; $logger = new DUP_DupArchive_Logger(); DupArchiveEngine::init($logger, 'DUP_Log::profile'); $embedded_scan_ark_file_path = $this->getEmbeddedScanFilePath(); DupArchiveEngine::addRelativeFileToArchiveST($archive_filepath, $scan_filepath, $embedded_scan_ark_file_path); $this->numFilesAdded++; if (file_exists($htaccess_filepath)) { $htaccess_ark_file_path = $this->getHtaccessArkFilePath(); try { DupArchiveEngine::addRelativeFileToArchiveST($archive_filepath, $htaccess_filepath, $htaccess_ark_file_path); $this->numFilesAdded++; } catch (Exception $ex) { // Non critical so bury exception } } if (file_exists($webconf_filepath)) { try { DupArchiveEngine::addRelativeFileToArchiveST($archive_filepath, $webconf_filepath, DUPLICATOR_WEBCONFIG_ORIG_FILENAME); $this->numFilesAdded++; } catch (Exception $ex) { // Non critical so bury exception } } if (file_exists($wpconfig_filepath)) { $conf_ark_file_path = $this->getWPConfArkFilePath(); $temp_conf_ark_file_path = $this->getTempWPConfArkFilePath(); if (copy($wpconfig_filepath, $temp_conf_ark_file_path)) { $this->cleanTempWPConfArkFilePath($temp_conf_ark_file_path); DupArchiveEngine::addRelativeFileToArchiveST($archive_filepath, $temp_conf_ark_file_path, $conf_ark_file_path); } else { DupArchiveEngine::addRelativeFileToArchiveST($archive_filepath, $wpconfig_filepath, $conf_ark_file_path); } $this->numFilesAdded++; } $this->add_installer_files_using_duparchive($archive_filepath, $installer_filepath, $archive_config_filepath); $success = true; } catch (Exception $ex) { DUP_Log::error("Error adding installer files to archive. ", $ex->getMessage(), Dup_ErrorBehavior::ThrowException); } return $success; } private function add_installer_files_using_duparchive($archive_filepath, $installer_filepath, $archive_config_filepath) { $installer_backup_filename = $this->Package->NameHash.'_installer-backup.php'; DUP_Log::Info('Adding enhanced installer files to archive using DupArchive'); DupArchiveEngine::addRelativeFileToArchiveST($archive_filepath, $installer_filepath, $installer_backup_filename); $this->numFilesAdded++; $base_installer_directory = DUPLICATOR_PLUGIN_PATH.'installer'; $installer_directory = "$base_installer_directory/dup-installer"; $counts = DupArchiveEngine::addDirectoryToArchiveST($archive_filepath, $installer_directory, $base_installer_directory, true); $this->numFilesAdded += $counts->numFilesAdded; $this->numDirsAdded += $counts->numDirsAdded; $archive_config_relative_path = $this->getArchiveTxtFilePath(); DupArchiveEngine::addRelativeFileToArchiveST($archive_filepath, $archive_config_filepath, $archive_config_relative_path); $this->numFilesAdded++; // Include dup archive $duparchive_lib_directory = DUPLICATOR_PLUGIN_PATH.'lib/dup_archive'; $duparchive_lib_counts = DupArchiveEngine::addDirectoryToArchiveST($archive_filepath, $duparchive_lib_directory, DUPLICATOR_PLUGIN_PATH, true, 'dup-installer/'); $this->numFilesAdded += $duparchive_lib_counts->numFilesAdded; $this->numDirsAdded += $duparchive_lib_counts->numDirsAdded; // Include snaplib $snaplib_directory = DUPLICATOR_PLUGIN_PATH.'lib/snaplib'; $snaplib_counts = DupArchiveEngine::addDirectoryToArchiveST($archive_filepath, $snaplib_directory, DUPLICATOR_PLUGIN_PATH, true, 'dup-installer/'); $this->numFilesAdded += $snaplib_counts->numFilesAdded; $this->numDirsAdded += $snaplib_counts->numDirsAdded; // Include fileops $fileops_directory = DUPLICATOR_PLUGIN_PATH.'lib/fileops'; $fileops_counts = DupArchiveEngine::addDirectoryToArchiveST($archive_filepath, $fileops_directory, DUPLICATOR_PLUGIN_PATH, true, 'dup-installer/'); $this->numFilesAdded += $fileops_counts->numFilesAdded; $this->numDirsAdded += $fileops_counts->numDirsAdded; // Include config $config_directory = DUPLICATOR_PLUGIN_PATH.'lib/config'; $config_counts = DupArchiveEngine::addDirectoryToArchiveST($archive_filepath, $config_directory, DUPLICATOR_PLUGIN_PATH, true, 'dup-installer/'); $this->numFilesAdded += $config_counts->numFilesAdded; $this->numDirsAdded += $fileops_counts->numDirsAdded; } private function add_extra_files_using_ziparchive($installer_filepath, $scan_filepath, $sql_filepath, $zip_filepath, $archive_config_filepath, $wpconfig_filepath) { $htaccess_filepath = $this->getHtaccessFilePath(); $webconfig_filepath = duplicator_get_abs_path().'/web.config'; $success = false; $zipArchive = new ZipArchive(); if ($zipArchive->open($zip_filepath, ZIPARCHIVE::CREATE) === TRUE) { DUP_Log::Info("Successfully opened zip $zip_filepath"); if (file_exists($htaccess_filepath)) { $htaccess_ark_file_path = $this->getHtaccessArkFilePath(); DUP_Zip_U::addFileToZipArchive($zipArchive, $htaccess_filepath, $htaccess_ark_file_path, true); } if (file_exists($webconfig_filepath)) { DUP_Zip_U::addFileToZipArchive($zipArchive, $webconfig_filepath, DUPLICATOR_WEBCONFIG_ORIG_FILENAME, true); } if (!empty($wpconfig_filepath)) { $conf_ark_file_path = $this->getWPConfArkFilePath(); $temp_conf_ark_file_path = $this->getTempWPConfArkFilePath(); if (copy($wpconfig_filepath, $temp_conf_ark_file_path)) { $this->cleanTempWPConfArkFilePath($temp_conf_ark_file_path); DUP_Zip_U::addFileToZipArchive($zipArchive, $temp_conf_ark_file_path, $conf_ark_file_path, true); } else { DUP_Zip_U::addFileToZipArchive($zipArchive, $wpconfig_filepath, $conf_ark_file_path, true); } } $embedded_scan_file_path = $this->getEmbeddedScanFilePath(); if (DUP_Zip_U::addFileToZipArchive($zipArchive, $scan_filepath, $embedded_scan_file_path, true)) { if ($this->add_installer_files_using_zip_archive($zipArchive, $installer_filepath, $archive_config_filepath, true)) { DUP_Log::info("Installer files added to archive"); DUP_Log::info("Added to archive"); $success = true; } else { DUP_Log::error("Unable to add enhanced enhanced installer files to archive.", '', Dup_ErrorBehavior::LogOnly); } } else { DUP_Log::error("Unable to add scan file to archive.", '', Dup_ErrorBehavior::LogOnly); } if ($zipArchive->close() === false) { DUP_Log::error("Couldn't close archive when adding extra files.", ''); $success = false; } DUP_Log::Info('After ziparchive close when adding installer'); } return $success; } // Add installer directory to the archive and the archive.cfg private function add_installer_files_using_zip_archive(&$zip_archive, $installer_filepath, $archive_config_filepath, $is_compressed) { $success = false; $installer_backup_filename = $this->Package->NameHash.'_installer-backup.php'; DUP_Log::Info('Adding enhanced installer files to archive using ZipArchive'); if (DUP_Zip_U::addFileToZipArchive($zip_archive, $installer_filepath, $installer_backup_filename, true)) { DUPLICATOR_PLUGIN_PATH.'installer/'; $installer_directory = DUPLICATOR_PLUGIN_PATH.'installer/dup-installer'; if (DUP_Zip_U::addDirWithZipArchive($zip_archive, $installer_directory, true, '', $is_compressed)) { $archive_config_local_name = $this->getArchiveTxtFilePath(); if (DUP_Zip_U::addFileToZipArchive($zip_archive, $archive_config_filepath, $archive_config_local_name, true)) { $snaplib_directory = DUPLICATOR_PLUGIN_PATH.'lib/snaplib'; $config_directory = DUPLICATOR_PLUGIN_PATH.'lib/config'; if (DUP_Zip_U::addDirWithZipArchive($zip_archive, $snaplib_directory, true, 'dup-installer/lib/', $is_compressed) && DUP_Zip_U::addDirWithZipArchive($zip_archive, $config_directory, true, 'dup-installer/lib/', $is_compressed) ) { $success = true; } else { DUP_Log::error("Error adding directory {$snaplib_directory} and {$config_directory} to zipArchive", '', Dup_ErrorBehavior::LogOnly); } } else { DUP_Log::error("Error adding $archive_config_filepath to zipArchive", '', Dup_ErrorBehavior::LogOnly); } } else { DUP_Log::error("Error adding directory $installer_directory to zipArchive", '', Dup_ErrorBehavior::LogOnly); } } else { DUP_Log::error("Error adding backup installer file to zipArchive", '', Dup_ErrorBehavior::LogOnly); } return $success; } /** * Get .htaccess file path * * @return string */ private function getHtaccessFilePath() { return duplicator_get_abs_path().'/.htaccess'; } /** * Get .htaccss in archive file * * @return string */ private function getHtaccessArkFilePath() { $packageHash = $this->Package->getPackageHash(); $htaccessArkFilePath = '.htaccess__'.$packageHash; return $htaccessArkFilePath; } /** * Get wp-config.php file path along with name in archive file */ private function getWPConfArkFilePath() { if (DUPLICATOR_INSTALL_SITE_OVERWRITE_ON) { $package_hash = $this->Package->getPackageHash(); $conf_ark_file_path = 'dup-wp-config-arc__'.$package_hash.'.txt'; } else { $conf_ark_file_path = 'wp-config.php'; } return $conf_ark_file_path; } /** * Get temp wp-config.php file path along with name in temp folder */ private function getTempWPConfArkFilePath() { $temp_conf_ark_file_path = DUP_Settings::getSsdirTmpPath().'/'.$this->Package->NameHash.'_wp-config.txt'; return $temp_conf_ark_file_path; } /** * Clear out sensitive database connection information * * @param $temp_conf_ark_file_path Temp config file path */ private static function cleanTempWPConfArkFilePath($temp_conf_ark_file_path) { if (function_exists('token_get_all')) { require_once(DUPLICATOR_PLUGIN_PATH.'lib/config/class.wp.config.tranformer.php'); $transformer = new DupLiteWPConfigTransformer($temp_conf_ark_file_path); $constants = array('DB_NAME', 'DB_USER', 'DB_PASSWORD', 'DB_HOST'); foreach ($constants as $constant) { if ($transformer->exists('constant', $constant)) { $transformer->update('constant', $constant, ''); } } } } /** * Get scan.json file path along with name in archive file */ private function getEmbeddedScanFilePath() { $package_hash = $this->Package->getPackageHash(); $embedded_scan_ark_file_path = 'dup-installer/dup-scan__'.$package_hash.'.json'; return $embedded_scan_ark_file_path; } /** * Get archive.txt file path along with name in archive file */ private function getArchiveTxtFilePath() { $package_hash = $this->Package->getPackageHash(); $archive_txt_file_path = 'dup-installer/dup-archive__'.$package_hash.'.txt'; return $archive_txt_file_path; } } package/duparchive/class.pack.archive.duparchive.state.create.php 0000644 00000005327 15133151516 0021166 0 ustar 00 <?php defined('ABSPATH') || defined('DUPXABSPATH') || exit; /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ require_once (DUPLICATOR_PLUGIN_PATH.'lib/dup_archive/classes/states/class.duparchive.state.create.php'); require_once (DUPLICATOR_PLUGIN_PATH.'lib/dup_archive/classes/class.duparchive.processing.failure.php'); class DUP_DupArchive_Create_State extends DupArchiveCreateState { /* @var $package DUP_Package */ // private $package; // public function setPackage(&$package) public function setPackage(&$package) { // $this->package = &$package; } // Only one active package so straightforward // public static function createFromPackage(&$package) public static function get_instance() { $instance = new DUP_DupArchive_Create_State(); $data = DUP_Settings::Get('duparchive_create_state'); DUP_Util::objectCopy($data, $instance); $instance->startTimestamp = time(); DUP_Log::TraceObject("retrieving create state", $instance); return $instance; } public static function createNew($archivePath, $basePath, $timeSliceInSecs, $isCompressed, $setArchiveOffsetToEndOfArchive) { $instance = new DUP_DupArchive_Create_State(); if ($setArchiveOffsetToEndOfArchive) { $instance->archiveOffset = filesize($archivePath); } else { $instance->archiveOffset = 0; } $instance->archivePath = $archivePath; $instance->basePath = $basePath; $instance->currentDirectoryIndex = 0; $instance->currentFileOffset = 0; $instance->currentFileIndex = 0; $instance->failures = array(); $instance->globSize = DupArchiveCreateState::DEFAULT_GLOB_SIZE; $instance->isCompressed = $isCompressed; $instance->timeSliceInSecs = $timeSliceInSecs; $instance->working = true; $instance->skippedDirectoryCount = 0; $instance->skippedFileCount = 0; $instance->startTimestamp = time(); return $instance; } public function addFailure($type, $subject, $description, $isCritical = false) { parent::addFailure($type, $subject, $description, $isCritical); } public function save() { DUP_Log::TraceObject("Saving create state", $this); DUP_Settings::Set('duparchive_create_state', $this); DUP_Settings::Save(); } } package/duparchive/class.pack.archive.duparchive.php 0000644 00000040157 15133151516 0016605 0 ustar 00 <?php defined('ABSPATH') || defined('DUPXABSPATH') || exit; require_once (DUPLICATOR_PLUGIN_PATH.'classes/package/duparchive/class.pack.archive.duparchive.state.expand.php'); require_once (DUPLICATOR_PLUGIN_PATH.'classes/package/duparchive/class.pack.archive.duparchive.state.create.php'); require_once (DUPLICATOR_PLUGIN_PATH.'lib/dup_archive/classes/class.duparchive.loggerbase.php'); require_once (DUPLICATOR_PLUGIN_PATH.'lib/dup_archive/classes/class.duparchive.engine.php'); require_once (DUPLICATOR_PLUGIN_PATH.'lib/dup_archive/classes/states/class.duparchive.state.create.php'); require_once (DUPLICATOR_PLUGIN_PATH.'lib/dup_archive/classes/states/class.duparchive.state.expand.php'); require_once (DUPLICATOR_PLUGIN_PATH.'lib/dup_archive/classes/class.duparchive.processing.failure.php'); class DUP_DupArchive_Logger extends DupArchiveLoggerBase { public function log($s, $flush = false, $callingFunctionOverride = null) { DUP_Log::Trace($s, true, $callingFunctionOverride); } } class DUP_DupArchive { // Using a worker time override since evidence shorter time works much const WorkerTimeInSec = 10; /** * CREATE * Creates the zip file and adds the SQL file to the archive */ public static function create($archive, $buildProgress, $package) { /* @var $buildProgress DUP_Build_Progress */ DUP_LOG::trace("start"); try { DUP_Log::Open($package->NameHash); if ($buildProgress->retries > DUPLICATOR_MAX_BUILD_RETRIES) { $error_msg = __('Package build appears stuck so marking package as failed. Is the Max Worker Time set too high?.', 'duplicator'); DUP_Log::error(esc_html__('Build Failure', 'duplicator'), esc_html($error_msg), Dup_ErrorBehavior::LogOnly); //$buildProgress->failed = true; $buildProgress->set_failed($error_msg); $package->setStatus(DUP_PackageStatus::ERROR); ; return true; } else { // If all goes well retries will be reset to 0 at the end of this function. $buildProgress->retries++; $package->update(); } $done = false; DupArchiveEngine::init(new DUP_DupArchive_Logger(), null, $archive); DUP_Package::safeTmpCleanup(true); $compressDir = rtrim(DUP_Util::safePath($archive->PackDir), '/'); $sqlPath = DUP_Settings::getSsdirTmpPath()."/{$package->Database->File}"; $archivePath = DUP_Settings::getSsdirTmpPath()."/{$archive->File}"; $scanFilepath = DUP_Settings::getSsdirTmpPath()."/{$package->NameHash}_scan.json"; $skipArchiveFinalization = false; $json = ''; if (file_exists($scanFilepath)) { $json = file_get_contents($scanFilepath); if (empty($json)) { $errorText = __("Scan file $scanFilepath is empty!", 'duplicator'); $fixText = __("Click on \"Resolve This\" button to fix the JSON settings.", 'duplicator'); DUP_Log::Trace($errorText); DUP_Log::error(esc_html($errorText)." **RECOMMENDATION: ".esc_html($fixText).".", '', Dup_ErrorBehavior::LogOnly); //$buildProgress->failed = true; $buildProgress->set_failed($errorText); $package->setStatus(DUP_PackageStatus::ERROR); return true; } } else { DUP_Log::trace("**** scan file $scanFilepath doesn't exist!!"); $errorMessage = sprintf(__("ERROR: Can't find Scanfile %s. Please ensure there no non-English characters in the package or schedule name.", 'duplicator'), $scanFilepath); DUP_Log::error($errorMessage, '', Dup_ErrorBehavior::LogOnly); //$buildProgress->failed = true; $buildProgress->set_failed($errorMessage); $package->setStatus(DUP_PackageStatus::ERROR); return true; } Dup_Log::TraceObject("buildprogress object", $buildProgress, false); $scanReport = json_decode($json); if ($buildProgress->archive_started == false) { $filterDirs = empty($archive->FilterDirs) ? 'not set' : $archive->FilterDirs; $filterExts = empty($archive->FilterExts) ? 'not set' : $archive->FilterExts; $filterFiles = empty($archive->FilterFiles) ? 'not set' : $archive->FilterFiles; $filterOn = ($archive->FilterOn) ? 'ON' : 'OFF'; $filterDirsFormat = rtrim(str_replace(';', "\n\t", $filterDirs)); $filterFilesFormat = rtrim(str_replace(';', "\n\t", $filterFiles)); DUP_Log::info("\n********************************************************************************"); DUP_Log::info("ARCHIVE Type=DUP Mode=DupArchive"); DUP_Log::info("********************************************************************************"); DUP_Log::info("ARCHIVE DIR: ".$compressDir); DUP_Log::info("ARCHIVE FILE: ".basename($archivePath)); DUP_Log::info("FILTERS: *{$filterOn}*"); DUP_Log::Info("DIRS:\n\t{$filterDirsFormat}"); DUP_Log::Info("FILES:\n\t{$filterFilesFormat}"); DUP_Log::info("EXTS: {$filterExts}"); DUP_Log::info("----------------------------------------"); DUP_Log::info("COMPRESSING"); DUP_Log::info("SIZE:\t".$scanReport->ARC->Size); DUP_Log::info("STATS:\tDirs ".$scanReport->ARC->DirCount." | Files ".$scanReport->ARC->FileCount." | Total ".$scanReport->ARC->FullCount); if (($scanReport->ARC->DirCount == '') || ($scanReport->ARC->FileCount == '') || ($scanReport->ARC->FullCount == '')) { $error_message = 'Invalid Scan Report Detected'; DUP_Log::error($error_message, 'Invalid Scan Report Detected', Dup_ErrorBehavior::LogOnly); $buildProgress->set_failed($error_message); $package->setStatus(DUP_PackageStatus::ERROR); return true; } try { DupArchiveEngine::createArchive($archivePath, true); $sql_ark_file_path = $package->getSqlArkFilePath(); DupArchiveEngine::addRelativeFileToArchiveST($archivePath, $sqlPath, $sql_ark_file_path); } catch (Exception $ex) { $error_message = 'Error adding database.sql to archive'; DUP_Log::error($error_message, $ex->getMessage(), Dup_ErrorBehavior::LogOnly); $buildProgress->set_failed($error_message); $package->setStatus(DUP_PackageStatus::ERROR); return true; } $buildProgress->archive_started = true; $buildProgress->retries = 0; $createState = DUP_DupArchive_Create_State::createNew($archivePath, $compressDir, self::WorkerTimeInSec, true, true); $createState->throttleDelayInUs = 0; $createState->save(); $package->Update(); } try { $createState = DUP_DupArchive_Create_State::get_instance(); if ($buildProgress->retries > 1) { // Indicates it had problems before so move into robustness mode $createState->isRobust = true; $createState->save(); } if ($createState->working) { DUP_LOG::Trace("Create state is working"); //die(0);//rsr // DupArchiveEngine::addItemsToArchive($createState, $scanReport->ARC, $archive); DupArchiveEngine::addItemsToArchive($createState, $scanReport->ARC); $buildProgress->set_build_failures($createState->failures); if ($createState->isCriticalFailurePresent()) { throw new Exception($createState->getFailureSummary()); } $totalFileCount = count($scanReport->ARC->Files); $package->Status = DupLiteSnapLibUtil::getWorkPercent(DUP_PackageStatus::ARCSTART, DUP_PackageStatus::ARCVALIDATION, $totalFileCount, $createState->currentFileIndex); $buildProgress->retries = 0; $createState->save(); DUP_LOG::TraceObject("Stored Create State", $createState); DUP_LOG::TraceObject('Stored build_progress', $package->BuildProgress); if ($createState->working == false) { // Want it to do the final cleanup work in an entirely new thread so return immediately $skipArchiveFinalization = true; DUP_LOG::TraceObject("Done build phase. Create State=", $createState); } } } catch (Exception $ex) { $message = __('Problem adding items to archive.', 'duplicator').' '.$ex->getMessage(); DUP_Log::error(__('Problems adding items to archive.', 'duplicator'), $message, Dup_ErrorBehavior::LogOnly); DUP_Log::TraceObject($message." EXCEPTION:", $ex); //$buildProgress->failed = true; $buildProgress->set_failed($message); $package->setStatus(DUP_PackageStatus::ERROR); return true; } //-- Final Wrapup of the Archive if ((!$skipArchiveFinalization) && ($createState->working == false)) { DUP_LOG::Trace("Create state is not working and not skip archive finalization"); if (!$buildProgress->installer_built) { if ($package->Installer->build($package, false)) { $package->Runtime = -1; $package->ExeSize = DUP_Util::byteSize($package->Installer->Size); $package->ZipSize = DUP_Util::byteSize($package->Archive->Size); $package->update(); } else { $package->update(); return; } DUP_Log::Trace("Installer has been built so running expand now"); $expandState = DUP_DupArchive_Expand_State::getInstance(true); $expandState->archivePath = $archivePath; $expandState->working = true; $expandState->timeSliceInSecs = self::WorkerTimeInSec; $expandState->basePath = DUP_Settings::getSsdirTmpPath().'/validate'; $expandState->throttleDelayInUs = 0; // RSR TODO $expandState->validateOnly = true; $expandState->validationType = DupArchiveValidationTypes::Standard; $expandState->working = true; $expandState->expectedDirectoryCount = count($scanReport->ARC->Dirs) - $createState->skippedDirectoryCount + $package->Installer->numDirsAdded; $expandState->expectedFileCount = count($scanReport->ARC->Files) + 1 - $createState->skippedFileCount + $package->Installer->numFilesAdded; // database.sql will be in there $expandState->save(); $sfc = count($scanReport->ARC->Files); $nfa = $package->Installer->numFilesAdded; Dup_Log::trace("####scan files {$sfc} skipped files {$createState->skippedFileCount} num files added {$nfa}"); DUP_LOG::traceObject("EXPAND STATE AFTER SAVE", $expandState); } else { try { $expandState = DUP_DupArchive_Expand_State::getInstance(); if ($buildProgress->retries > 1) { // Indicates it had problems before so move into robustness mode $expandState->isRobust = true; $expandState->save(); } DUP_Log::traceObject('Resumed validation expand state', $expandState); DupArchiveEngine::expandArchive($expandState); $buildProgress->set_validation_failures($expandState->failures); $totalFileCount = count($scanReport->ARC->Files); $archiveSize = @filesize($expandState->archivePath); $package->Status = DupLiteSnapLibUtil::getWorkPercent(DUP_PackageStatus::ARCVALIDATION, DUP_PackageStatus::COMPLETE, $archiveSize, $expandState->archiveOffset); DUP_LOG::TraceObject("package status after expand=", $package->Status); DUP_LOG::Trace("archive size:{$archiveSize} expand offset:{$expandState->archiveOffset}"); } catch (Exception $ex) { DUP_Log::Trace('Exception:'.$ex->getMessage().':'.$ex->getTraceAsString()); $buildProgress->set_failed('Error validating archive'); $package->setStatus(DUP_PackageStatus::ERROR); return true; } if ($expandState->isCriticalFailurePresent()) { // Fail immediately if critical failure present - even if havent completed processing the entire archive. $error_message = __('Critical failure present in validation', 'duplicator'); DUP_Log::error($error_message, $expandState->getFailureSummary(), Dup_ErrorBehavior::LogOnly); $buildProgress->set_failed($error_message); return true; } else if (!$expandState->working) { $buildProgress->archive_built = true; $buildProgress->retries = 0; $package->update(); $timerAllEnd = DUP_Util::getMicrotime(); $timerAllSum = DUP_Util::elapsedTime($timerAllEnd, $package->TimerStart); DUP_LOG::traceObject("create state", $createState); $archiveFileSize = @filesize($archivePath); DUP_Log::info("COMPRESSED SIZE: ".DUP_Util::byteSize($archiveFileSize)); DUP_Log::info("ARCHIVE RUNTIME: {$timerAllSum}"); DUP_Log::info("MEMORY STACK: ".DUP_Server::getPHPMemory()); DUP_Log::info("CREATE WARNINGS: ".$createState->getFailureSummary(false, true)); DUP_Log::info("VALIDATION WARNINGS: ".$expandState->getFailureSummary(false, true)); $archive->file_count = $expandState->fileWriteCount + $expandState->directoryWriteCount; $package->update(); $done = true; } else { $expandState->save(); } } } } catch (Exception $ex) { // Have to have a catchall since the main system that calls this function is not prepared to handle exceptions DUP_Log::trace('Top level create Exception:'.$ex->getMessage().':'.$ex->getTraceAsString()); //$buildProgress->failed = true; $buildProgress->set_failed('Error encoundtered creating archive. See package log'); return true; } $buildProgress->retries = 0; return $done; } } package/duparchive/class.pack.archive.duparchive.state.expand.php 0000644 00000012524 15133151516 0021177 0 ustar 00 <?php defined('ABSPATH') || defined('DUPXABSPATH') || exit; /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ require_once (DUPLICATOR_PLUGIN_PATH.'lib/dup_archive/classes/states/class.duparchive.state.expand.php'); class DUP_DupArchive_Expand_State extends DupArchiveExpandState { public static function getInstance($reset = false) { $instance = new DUP_DupArchive_Expand_State(); if ($reset) { $instance->initMembers(); } else { $instance->loadMembers(); } return $instance; } private function loadMembers() { $data = DUP_Settings::Get('duparchive_expand_state'); DUP_LOG::traceObject("****RAW EXPAND STATE LOADED****", $data); if($data->currentFileHeaderString != null) { $this->currentFileHeader = DUP_JSON::decode($data->currentFileHeaderString); } else { $this->currentFileHeader = null; } if($data->archiveHeaderString != null) { $this->archiveHeader = DUP_JSON::decode($data->archiveHeaderString); } else { $this->archiveHeader = null; } if ($data->failuresString) { $this->failures = DUP_JSON::decode($data->failuresString); } else { $this->failures = array(); } DUP_Util::objectCopy($data, $this, array('archiveHeaderString', 'currentFileHeaderString', 'failuresString')); // // $this->archiveOffset = $data->archiveOffset; // $this->archivePath = $data->archivePath; // $this->basePath = $data->basePath; // $this->currentFileOffset = $data->currentFileOffset; // $this->failures = $data->failures; // $this->isCompressed = $data->isCompressed; // $this->startTimestamp = $data->startTimestamp; // $this->timeSliceInSecs = $data->timeSliceInSecs; // $this->fileWriteCount = $data->fileWriteCount; // $this->directoryWriteCount = $data->directoryWriteCount; // $this->working = $data->working; // $this->directoryModeOverride = $data->directoryModeOverride; // $this->fileModeOverride = $data->fileModeOverride; // $this->throttleDelayInUs = $data->throttleDelayInUs; // $this->validateOnly = $data->validateOnly; // $this->validationType = $data->validationType; } public function save() { $data = new stdClass(); if($this->currentFileHeader != null) { $data->currentFileHeaderString = DupLiteSnapJsonU::wp_json_encode($this->currentFileHeader); } else { $data->currentFileHeaderString = null; } if($this->archiveHeader != null) { $data->archiveHeaderString = DupLiteSnapJsonU::wp_json_encode($this->archiveHeader); } else { $data->archiveHeaderString = null; } $data->failuresString = DupLiteSnapJsonU::wp_json_encode($this->failures); // Object members auto skipped DUP_Util::objectCopy($this, $data); // $data->archiveOffset = $this->archiveOffset; // $data->archivePath = $this->archivePath; // $data->basePath = $this->basePath; // $data->currentFileOffset = $this->currentFileOffset; // $data->failures = $this->failures; // $data->isCompressed = $this->isCompressed; // $data->startTimestamp = $this->startTimestamp; // $data->timeSliceInSecs = $this->timeSliceInSecs; // $data->fileWriteCount = $this->fileWriteCount; // $data->directoryWriteCount = $this->directoryWriteCount; // $data->working = $this->working; // $data->directoryModeOverride = $this->directoryModeOverride; // $data->fileModeOverride = $this->fileModeOverride; // $data->throttleDelayInUs = $this->throttleDelayInUs; // $data->validateOnly = $this->validateOnly; // $data->validationType = $this->validationType; DUP_LOG::traceObject("****SAVING EXPAND STATE****", $this); DUP_LOG::traceObject("****SERIALIZED STATE****", $data); DUP_Settings::Set('duparchive_expand_state', $data); DUP_Settings::Save(); } private function initMembers() { $this->currentFileHeader = null; $this->archiveOffset = 0; $this->archiveHeader = null; $this->archivePath = null; $this->basePath = null; $this->currentFileOffset = 0; $this->failures = array(); $this->isCompressed = false; $this->startTimestamp = time(); $this->timeSliceInSecs = -1; $this->working = false; $this->validateOnly = false; $this->directoryModeOverride = -1; $this->fileModeOverride = -1; $this->throttleDelayInUs = 0; } } package/duparchive/index.php 0000644 00000000016 15133151516 0012107 0 ustar 00 <?php //silent package/class.pack.archive.zip.php 0000644 00000026247 15133151516 0013127 0 ustar 00 <?php defined('ABSPATH') || defined('DUPXABSPATH') || exit; // Exit if accessed directly if (! defined('DUPLICATOR_VERSION')) exit; require_once (DUPLICATOR_PLUGIN_PATH.'classes/package/class.pack.archive.php'); /** * Creates a zip file using the built in PHP ZipArchive class */ class DUP_Zip extends DUP_Archive { //PRIVATE private static $compressDir; private static $countDirs = 0; private static $countFiles = 0; private static $sqlPath; private static $zipPath; private static $zipFileSize; private static $zipArchive; private static $limitItems = 0; private static $networkFlush = false; private static $scanReport; /** * Creates the zip file and adds the SQL file to the archive */ public static function create(DUP_Archive $archive, $buildProgress) { try { $timerAllStart = DUP_Util::getMicrotime(); $package_zip_flush = DUP_Settings::Get('package_zip_flush'); self::$compressDir = rtrim(wp_normalize_path(DUP_Util::safePath($archive->PackDir)), '/'); self::$sqlPath = DUP_Settings::getSsdirTmpPath()."/{$archive->Package->Database->File}"; self::$zipPath = DUP_Settings::getSsdirTmpPath()."/{$archive->File}"; self::$zipArchive = new ZipArchive(); self::$networkFlush = empty($package_zip_flush) ? false : $package_zip_flush; $filterDirs = empty($archive->FilterDirs) ? 'not set' : $archive->FilterDirs; $filterExts = empty($archive->FilterExts) ? 'not set' : $archive->FilterExts; $filterFiles = empty($archive->FilterFiles) ? 'not set' : $archive->FilterFiles; $filterOn = ($archive->FilterOn) ? 'ON' : 'OFF'; $filterDirsFormat = rtrim(str_replace(';', "\n\t", $filterDirs)); $filterFilesFormat = rtrim(str_replace(';', "\n\t", $filterFiles)); $lastDirSuccess = self::$compressDir; //LOAD SCAN REPORT $json = file_get_contents(DUP_Settings::getSsdirTmpPath()."/{$archive->Package->NameHash}_scan.json"); self::$scanReport = json_decode($json); DUP_Log::Info("\n********************************************************************************"); DUP_Log::Info("ARCHIVE (ZIP):"); DUP_Log::Info("********************************************************************************"); $isZipOpen = (self::$zipArchive->open(self::$zipPath, ZIPARCHIVE::CREATE) === TRUE); if (!$isZipOpen) { $error_message = "Cannot open zip file with PHP ZipArchive."; $buildProgress->set_failed($error_message); DUP_Log::error($error_message, "Path location [".self::$zipPath."]", Dup_ErrorBehavior::LogOnly); $archive->Package->setStatus(DUP_PackageStatus::ERROR); return; } DUP_Log::Info("ARCHIVE DIR: ".self::$compressDir); DUP_Log::Info("ARCHIVE FILE: ".basename(self::$zipPath)); DUP_Log::Info("FILTERS: *{$filterOn}*"); DUP_Log::Info("DIRS:\n\t{$filterDirsFormat}"); DUP_Log::Info("FILES:\n\t{$filterFilesFormat}"); DUP_Log::Info("EXTS: {$filterExts}"); DUP_Log::Info("----------------------------------------"); DUP_Log::Info("COMPRESSING"); DUP_Log::Info("SIZE:\t".self::$scanReport->ARC->Size); DUP_Log::Info("STATS:\tDirs ".self::$scanReport->ARC->DirCount." | Files ".self::$scanReport->ARC->FileCount); //ADD SQL $sql_ark_file_path = $archive->Package->getSqlArkFilePath(); $isSQLInZip = self::$zipArchive->addFile(self::$sqlPath, $sql_ark_file_path); if ($isSQLInZip) { DUP_Log::Info("SQL ADDED: ".basename(self::$sqlPath)); } else { $error_message = "Unable to add database.sql to archive."; DUP_Log::error($error_message, "SQL File Path [".self::$sqlPath."]", Dup_ErrorBehavior::LogOnly); $buildProgress->set_failed($error_message); $archive->Package->setStatus(DUP_PackageStatus::ERROR); return; } self::$zipArchive->close(); self::$zipArchive->open(self::$zipPath, ZipArchive::CREATE); //ZIP DIRECTORIES $info = ''; foreach (self::$scanReport->ARC->Dirs as $dir) { $emptyDir = $archive->getLocalDirPath($dir); if (is_readable($dir) && self::$zipArchive->addEmptyDir($emptyDir)) { self::$countDirs++; $lastDirSuccess = $dir; } else { //Don't warn when dirtory is the root path if (strcmp($dir, rtrim(self::$compressDir, '/')) != 0) { $dir_path = strlen($dir) ? "[{$dir}]" : "[Read Error] - last successful read was: [{$lastDirSuccess}]"; $info .= "DIR: {$dir_path}\n"; } } } //LOG Unreadable DIR info if (strlen($info)) { DUP_Log::Info("\nWARNING: Unable to zip directories:"); DUP_Log::Info($info); } /** * count update for integrity check */ $sumItems = (self::$countDirs + self::$countFiles); /* ZIP FILES: Network Flush * This allows the process to not timeout on fcgi * setups that need a response every X seconds */ $totalFileCount = count(self::$scanReport->ARC->Files); $info = ''; if (self::$networkFlush) { foreach (self::$scanReport->ARC->Files as $file) { $file_size = @filesize($file); $localFileName = $archive->getLocalFilePath($file); if (is_readable($file)) { if (defined('DUPLICATOR_ZIP_ARCHIVE_ADD_FROM_STR') && DUPLICATOR_ZIP_ARCHIVE_ADD_FROM_STR && $file_size < DUP_Constants::ZIP_STRING_LIMIT && self::$zipArchive->addFromString($localFileName, file_get_contents($file))) { Dup_Log::Info("Adding {$file} to zip"); self::$limitItems++; self::$countFiles++; } elseif (self::$zipArchive->addFile($file, $localFileName)) { Dup_Log::Info("Adding {$file} to zip"); self::$limitItems++; self::$countFiles++; } else { $info .= "FILE: [{$file}]\n"; } } else { $info .= "FILE: [{$file}]\n"; } //Trigger a flush to the web server after so many files have been loaded. if (self::$limitItems > DUPLICATOR_ZIP_FLUSH_TRIGGER) { self::$zipArchive->close(); self::$zipArchive->open(self::$zipPath); self::$limitItems = 0; DUP_Util::fcgiFlush(); DUP_Log::Info("Items archived [{$sumItems}] flushing response."); } if(self::$countFiles % 500 == 0) { // Every so many files update the status so the UI can display $archive->Package->Status = DupLiteSnapLibUtil::getWorkPercent(DUP_PackageStatus::ARCSTART, DUP_PackageStatus::ARCVALIDATION, $totalFileCount, self::$countFiles); $archive->Package->update(); } } } //Normal else { foreach (self::$scanReport->ARC->Files as $file) { $file_size = @filesize($file); $localFileName = $archive->getLocalFilePath($file); if (is_readable($file)) { if (defined('DUPLICATOR_ZIP_ARCHIVE_ADD_FROM_STR') && DUPLICATOR_ZIP_ARCHIVE_ADD_FROM_STR && $file_size < DUP_Constants::ZIP_STRING_LIMIT && self::$zipArchive->addFromString($localFileName, file_get_contents($file))) { self::$countFiles++; } elseif (self::$zipArchive->addFile($file, $localFileName)) { self::$countFiles++; } else { $info .= "FILE: [{$file}]\n"; } } else { $info .= "FILE: [{$file}]\n"; } if(self::$countFiles % 500 == 0) { // Every so many files update the status so the UI can display $archive->Package->Status = DupLiteSnapLibUtil::getWorkPercent(DUP_PackageStatus::ARCSTART, DUP_PackageStatus::ARCVALIDATION, $totalFileCount, self::$countFiles); $archive->Package->update(); } } } //LOG Unreadable FILE info if (strlen($info)) { DUP_Log::Info("\nWARNING: Unable to zip files:"); DUP_Log::Info($info); unset($info); } DUP_Log::Info(print_r(self::$zipArchive, true)); /** * count update for integrity check */ $archive->file_count = self::$countDirs + self::$countFiles; DUP_Log::Info("FILE ADDED TO ZIP: ".$archive->file_count); //-------------------------------- //LOG FINAL RESULTS DUP_Util::fcgiFlush(); $zipCloseResult = self::$zipArchive->close(); if($zipCloseResult) { DUP_Log::Info("COMPRESSION RESULT: '{$zipCloseResult}'"); } else { $error_message = "ZipArchive close failure."; DUP_Log::error($error_message, "The ZipArchive engine is having issues zipping up the files on this server. For more details visit the FAQ\n" . "I'm getting a ZipArchive close failure when building. How can I resolve this?\n" . "[https://snapcreek.com/duplicator/docs/faqs-tech/#faq-package-165-q]", Dup_ErrorBehavior::LogOnly); $buildProgress->set_failed($error_message); $archive->Package->setStatus(DUP_PackageStatus::ERROR); return; } $timerAllEnd = DUP_Util::getMicrotime(); $timerAllSum = DUP_Util::elapsedTime($timerAllEnd, $timerAllStart); self::$zipFileSize = @filesize(self::$zipPath); DUP_Log::Info("COMPRESSED SIZE: ".DUP_Util::byteSize(self::$zipFileSize)); DUP_Log::Info("ARCHIVE RUNTIME: {$timerAllSum}"); DUP_Log::Info("MEMORY STACK: ".DUP_Server::getPHPMemory()); } catch (Exception $e) { $error_message = "Runtime error in class.pack.archive.zip.php constructor."; DUP_Log::error($error_message, "Exception: {$e}", Dup_ErrorBehavior::LogOnly); $buildProgress->set_failed($error_message); $archive->Package->setStatus(DUP_PackageStatus::ERROR); return; } } } package/class.pack.archive.filters.php 0000644 00000004461 15133151516 0013767 0 ustar 00 <?php defined('ABSPATH') || defined('DUPXABSPATH') || exit; /** * The base class for all filter types Directories/Files/Extentions * * @package Duplicator * @subpackage classes/package * */ // Exit if accessed directly if (! defined('DUPLICATOR_VERSION')) exit; class DUP_Archive_Filter_Scope_Base { //All internal storage items that duplicator decides to filter public $Core = array(); //Global filter items added from settings public $Global = array(); //Items when creating a package or template that a user decides to filter public $Instance = array(); } /** * The filter types that belong to directories * * @package Duplicator * @subpackage classes/package * */ class DUP_Archive_Filter_Scope_Directory extends DUP_Archive_Filter_Scope_Base { //Items that are not readable public $Warning = array(); //Items that are not readable public $Unreadable = array(); public $AddonSites = array(); } /** * The filter types that belong to files * * @package Duplicator * @subpackage classes/package * */ class DUP_Archive_Filter_Scope_File extends DUP_Archive_Filter_Scope_Directory { //Items that are too large public $Size = array(); } /** * The filter information object which store all information about the filtered * data that is gathered to the execution of a scan process * * @package Duplicator * @subpackage classes/package * */ class DUP_Archive_Filter_Info { //Contains all folder filter info public $Dirs = array(); //Contains all file filter info public $Files = array(); //Contains all extensions filter info public $Exts = array(); public $UDirCount = 0; public $UFileCount = 0; public $UExtCount = 0; public $TreeSize; public $TreeWarning; /** * Init this object */ public function __construct() { $this->reset(); } /** * reset and clean all object */ public function reset() { $this->Dirs = new DUP_Archive_Filter_Scope_Directory(); $this->Files = new DUP_Archive_Filter_Scope_File(); $this->Exts = new DUP_Archive_Filter_Scope_Base(); $this->TreeSize = array(); $this->TreeWarning = array(); } } package/class.pack.php 0000644 00000210722 15133151516 0010677 0 ustar 00 <?php defined('ABSPATH') || defined('DUPXABSPATH') || exit; // Exit if accessed directly if (! defined('DUPLICATOR_VERSION')) exit; require_once (DUPLICATOR_PLUGIN_PATH.'classes/utilities/class.u.php'); require_once (DUPLICATOR_PLUGIN_PATH.'classes/package/class.pack.archive.php'); require_once (DUPLICATOR_PLUGIN_PATH.'classes/package/class.pack.installer.php'); require_once (DUPLICATOR_PLUGIN_PATH.'classes/package/class.pack.database.php'); /** * Class used to keep track of the build progress * * @package Duplicator\classes */ class DUP_Build_Progress { public $thread_start_time; public $initialized = false; public $installer_built = false; public $archive_started = false; public $archive_has_database = false; public $archive_built = false; public $database_script_built = false; public $failed = false; public $retries = 0; public $build_failures = array(); public $validation_failures = array(); /** * * @var DUP_Package */ private $package; /** * * @param DUP_Package $package */ public function __construct($package) { $this->package = $package; } /** * * @return bool */ public function has_completed() { return $this->failed || ($this->installer_built && $this->archive_built && $this->database_script_built); } public function timed_out($max_time) { if ($max_time > 0) { $time_diff = time() - $this->thread_start_time; return ($time_diff >= $max_time); } else { return false; } } public function start_timer() { $this->thread_start_time = time(); } public function set_validation_failures($failures) { $this->validation_failures = array(); foreach ($failures as $failure) { $this->validation_failures[] = $failure; } } public function set_build_failures($failures) { $this->build_failures = array(); foreach ($failures as $failure) { $this->build_failures[] = $failure->description; } } public function set_failed($failure_message = null) { if($failure_message !== null) { $failure = new StdClass(); $failure->type = 0; $failure->subject = ''; $failure->description = $failure_message; $failure->isCritical = true; $this->build_failures[] = $failure; } $this->failed = true; $this->package->Status = DUP_PackageStatus::ERROR; } } /** * Class used to emulate and ENUM to give the status of a package from 0 to 100% * * @package Duplicator\classes */ final class DUP_PackageStatus { private function __construct() { } const ERROR = -1; const CREATED = 0; const START = 10; const DBSTART = 20; const DBDONE = 30; const ARCSTART = 40; const ARCVALIDATION = 60; const ARCDONE = 65; const COMPLETE = 100; } /** * Class used to emulate and ENUM to determine how the package was made. * For lite only the MANUAL type is used. * * @package Duplicator\classes */ final class DUP_PackageType { const MANUAL = 0; const SCHEDULED = 1; } /** * Class used to emulate and ENUM to determine the various file types used in a package * * @package Duplicator\classes */ abstract class DUP_PackageFileType { const Installer = 0; const Archive = 1; const SQL = 2; const Log = 3; const Scan = 4; } /** * Class used to store and process all Package logic * * Standard: PSR-2 * @link http://www.php-fig.org/psr/psr-2 * * @package Duplicator\classes */ class DUP_Package { const OPT_ACTIVE = 'duplicator_package_active'; //Properties public $Created; public $Version; public $VersionWP; public $VersionDB; public $VersionPHP; public $VersionOS; public $ID; public $Name; public $Hash; public $NameHash; //Set to DUP_PackageType public $Type; public $Notes; public $ScanFile; public $TimerStart = -1; public $Runtime; public $ExeSize; public $ZipSize; public $Status; public $WPUser; //Objects public $Archive; public $Installer; public $Database; public $BuildProgress; /** * Manages the Package Process */ function __construct() { $this->ID = null; $this->Version = DUPLICATOR_VERSION; $this->Type = DUP_PackageType::MANUAL; $this->Name = self::getDefaultName(); $this->Notes = null; $this->Database = new DUP_Database($this); $this->Archive = new DUP_Archive($this); $this->Installer = new DUP_Installer($this); $this->BuildProgress = new DUP_Build_Progress($this); $this->Status = DUP_PackageStatus::CREATED; } /** * Generates a JSON scan report * * @return array of scan results * * @notes: Testing = /wp-admin/admin-ajax.php?action=duplicator_package_scan */ public function runScanner() { $timerStart = DUP_Util::getMicrotime(); $report = array(); $this->ScanFile = "{$this->NameHash}_scan.json"; $report['RPT']['ScanTime'] = "0"; $report['RPT']['ScanFile'] = $this->ScanFile; //SERVER $srv = DUP_Server::getChecks(); $report['SRV'] = $srv['SRV']; //FILES $this->Archive->getScannerData(); $dirCount = count($this->Archive->Dirs); $fileCount = count($this->Archive->Files); $fullCount = $dirCount + $fileCount; $report['ARC']['Size'] = DUP_Util::byteSize($this->Archive->Size) or "unknown"; $report['ARC']['DirCount'] = number_format($dirCount); $report['ARC']['FileCount'] = number_format($fileCount); $report['ARC']['FullCount'] = number_format($fullCount); $report['ARC']['WarnFileCount'] = count($this->Archive->FilterInfo->Files->Warning); $report['ARC']['WarnDirCount'] = count($this->Archive->FilterInfo->Dirs->Warning); $report['ARC']['UnreadableDirCount'] = count($this->Archive->FilterInfo->Dirs->Unreadable); $report['ARC']['UnreadableFileCount'] = count($this->Archive->FilterInfo->Files->Unreadable); $report['ARC']['FilterDirsAll'] = $this->Archive->FilterDirsAll; $report['ARC']['FilterFilesAll'] = $this->Archive->FilterFilesAll; $report['ARC']['FilterExtsAll'] = $this->Archive->FilterExtsAll; $report['ARC']['FilterInfo'] = $this->Archive->FilterInfo; $report['ARC']['RecursiveLinks'] = $this->Archive->RecursiveLinks; $report['ARC']['UnreadableItems'] = array_merge($this->Archive->FilterInfo->Files->Unreadable,$this->Archive->FilterInfo->Dirs->Unreadable); $report['ARC']['Status']['Size'] = ($this->Archive->Size > DUPLICATOR_SCAN_SIZE_DEFAULT) ? 'Warn' : 'Good'; $report['ARC']['Status']['Names'] = (count($this->Archive->FilterInfo->Files->Warning) + count($this->Archive->FilterInfo->Dirs->Warning)) ? 'Warn' : 'Good'; $report['ARC']['Status']['UnreadableItems'] = !empty($this->Archive->RecursiveLinks) || !empty($report['ARC']['UnreadableItems'])? 'Warn' : 'Good'; /* $overwriteInstallerParams = apply_filters('duplicator_overwrite_params_data', array()); $package_can_be_migrate = !(isset($overwriteInstallerParams['mode_chunking']['value']) && $overwriteInstallerParams['mode_chunking']['value'] == 3 && isset($overwriteInstallerParams['mode_chunking']['formStatus']) && $overwriteInstallerParams['mode_chunking']['formStatus'] == 'st_infoonly'); */ $package_can_be_migrate = true; $report['ARC']['Status']['MigratePackage'] = $package_can_be_migrate ? 'Good' : 'Warn'; $report['ARC']['Status']['CanbeMigratePackage'] = $package_can_be_migrate; $privileges_to_show_create_proc_func = true; $procedures = $GLOBALS['wpdb']->get_col("SHOW PROCEDURE STATUS WHERE `Db` = '".$GLOBALS['wpdb']->dbname."'", 1); if (count($procedures)) { $create = $GLOBALS['wpdb']->get_row("SHOW CREATE PROCEDURE `".$procedures[0]."`", ARRAY_N); $privileges_to_show_create_proc_func = isset($create[2]); } $functions = $GLOBALS['wpdb']->get_col("SHOW FUNCTION STATUS WHERE `Db` = '".$GLOBALS['wpdb']->dbname."'", 1); if (count($functions)) { $create = $GLOBALS['wpdb']->get_row("SHOW CREATE FUNCTION `".$functions[0]."`", ARRAY_N); $privileges_to_show_create_proc_func = $privileges_to_show_create_proc_func && isset($create[2]); } $privileges_to_show_create_proc_func = apply_filters('duplicator_privileges_to_show_create_proc_func', $privileges_to_show_create_proc_func); $report['ARC']['Status']['showCreateProcFuncStatus'] = $privileges_to_show_create_proc_func ? 'Good' : 'Warn'; $report['ARC']['Status']['showCreateProcFunc'] = $privileges_to_show_create_proc_func; //$report['ARC']['Status']['Big'] = count($this->Archive->FilterInfo->Files->Size) ? 'Warn' : 'Good'; $report['ARC']['Dirs'] = $this->Archive->Dirs; $report['ARC']['Files'] = $this->Archive->Files; $report['ARC']['Status']['AddonSites'] = count($this->Archive->FilterInfo->Dirs->AddonSites) ? 'Warn' : 'Good'; //DATABASE $db = $this->Database->getScannerData(); $report['DB'] = $db; //Lite Limits $rawTotalSize = $this->Archive->Size + $report['DB']['RawSize']; $report['LL']['TotalSize'] = DUP_Util::byteSize($rawTotalSize); $report['LL']['Status']['TotalSize'] = ($rawTotalSize > DUPLICATOR_MAX_DUPARCHIVE_SIZE) ? 'Fail' : 'Good'; $warnings = array( $report['SRV']['SYS']['ALL'], $report['SRV']['WP']['ALL'], $report['ARC']['Status']['Size'], $report['ARC']['Status']['Names'], $db['Status']['DB_Size'], $db['Status']['DB_Rows'] ); //array_count_values will throw a warning message if it has null values, //so lets replace all nulls with empty string foreach ($warnings as $i => $value) { if (is_null($value)) { $warnings[$i] = ''; } } $warn_counts = is_array($warnings) ? array_count_values($warnings) : 0; $report['RPT']['Warnings'] = is_null($warn_counts['Warn']) ? 0 : $warn_counts['Warn']; $report['RPT']['Success'] = is_null($warn_counts['Good']) ? 0 : $warn_counts['Good']; $report['RPT']['ScanTime'] = DUP_Util::elapsedTime(DUP_Util::getMicrotime(), $timerStart); $fp = fopen(DUP_Settings::getSsdirTmpPath()."/{$this->ScanFile}", 'w'); fwrite($fp, DupLiteSnapJsonU::wp_json_encode_pprint($report)); fclose($fp); return $report; } /** * Validates the inputs from the UI for correct data input * * @return DUP_Validator */ public function validateInputs() { $validator = new DUP_Validator(); $validator->filter_custom($this->Name , DUP_Validator::FILTER_VALIDATE_NOT_EMPTY , array( 'valkey' => 'Name' , 'errmsg' => __('Package name can\'t be empty', 'duplicator'), ) ); $validator->explode_filter_custom($this->Archive->FilterDirs, ';' , DUP_Validator::FILTER_VALIDATE_FOLDER , array( 'valkey' => 'FilterDirs' , 'errmsg' => __('Directories: <b>%1$s</b> isn\'t a valid path', 'duplicator'), ) ); $validator->explode_filter_custom($this->Archive->FilterExts, ';' , DUP_Validator::FILTER_VALIDATE_FILE_EXT , array( 'valkey' => 'FilterExts' , 'errmsg' => __('File extension: <b>%1$s</b> isn\'t a valid extension', 'duplicator'), ) ); $validator->explode_filter_custom($this->Archive->FilterFiles, ';' , DUP_Validator::FILTER_VALIDATE_FILE , array( 'valkey' => 'FilterFiles' , 'errmsg' => __('Files: <b>%1$s</b> isn\'t a valid file name', 'duplicator'), ) ); //FILTER_VALIDATE_DOMAIN throws notice message on PHP 5.6 if (defined('FILTER_VALIDATE_DOMAIN')) { $validator->filter_var($this->Installer->OptsDBHost, FILTER_VALIDATE_DOMAIN , array( 'valkey' => 'OptsDBHost' , 'errmsg' => __('MySQL Server Host: <b>%1$s</b> isn\'t a valid host', 'duplicator'), 'acc_vals' => array( '' , 'localhost' ) ) ); } $validator->filter_var($this->Installer->OptsDBPort, FILTER_VALIDATE_INT , array( 'valkey' => 'OptsDBPort' , 'errmsg' => __('MySQL Server Port: <b>%1$s</b> isn\'t a valid port', 'duplicator'), 'acc_vals' => array( '' ), 'options' => array( 'min_range' => 0 ) ) ); return $validator; } /** * * @return string */ public function getInstDownloadName() { switch (DUP_Settings::Get('installer_name_mode')) { case DUP_Settings::INSTALLER_NAME_MODE_SIMPLE: return DUP_Installer::DEFAULT_INSTALLER_FILE_NAME_WITHOUT_HASH; case DUP_Settings::INSTALLER_NAME_MODE_WITH_HASH: default: return basename($this->getLocalPackageFile(DUP_PackageFileType::Installer)); } } /** * * @return bool return true if package is a active_package_id and status is bewteen 0 and 100 */ public function isRunning() { return DUP_Settings::Get('active_package_id') == $this->ID && $this->Status >= 0 && $this->Status < 100; } protected function cleanObjectBeforeSave() { $this->Archive->FilterInfo->reset(); } /** * Saves the active package to the package table * * @return void */ public function save($extension) { global $wpdb; $this->Archive->Format = strtoupper($extension); $this->Archive->File = "{$this->NameHash}_archive.{$extension}"; $this->Installer->File = apply_filters('duplicator_installer_file_path', "{$this->NameHash}_installer.php"); $this->Database->File = "{$this->NameHash}_database.sql"; $this->WPUser = isset($current_user->user_login) ? $current_user->user_login : 'unknown'; //START LOGGING DUP_Log::Open($this->NameHash); do_action('duplicator_lite_build_before_start' , $this); $this->writeLogHeader(); //CREATE DB RECORD $this->cleanObjectBeforeSave(); $packageObj = serialize($this); if (!$packageObj) { DUP_Log::error("Unable to serialize package object while building record."); } $this->ID = $this->getHashKey($this->Hash); if ($this->ID != 0) { DUP_LOG::Trace("ID non zero so setting to start"); $this->setStatus(DUP_PackageStatus::START); } else { DUP_LOG::Trace("ID IS zero so creating another package"); $tablePrefix = DUP_Util::getTablePrefix(); $results = $wpdb->insert($tablePrefix . "duplicator_packages", array( 'name' => $this->Name, 'hash' => $this->Hash, 'status' => DUP_PackageStatus::START, 'created' => current_time('mysql', get_option('gmt_offset', 1)), 'owner' => isset($current_user->user_login) ? $current_user->user_login : 'unknown', 'package' => $packageObj) ); if ($results === false) { $wpdb->print_error(); DUP_LOG::Trace("Problem inserting package: {$wpdb->last_error}"); DUP_Log::error("Duplicator is unable to insert a package record into the database table.", "'{$wpdb->last_error}'"); } $this->ID = $wpdb->insert_id; } do_action('duplicator_lite_build_start' , $this); } /** * Delete all files associated with this package ID * * @return void */ public function delete() { global $wpdb; $tablePrefix = DUP_Util::getTablePrefix(); $tblName = $tablePrefix.'duplicator_packages'; $getResult = $wpdb->get_results($wpdb->prepare("SELECT name, hash FROM `{$tblName}` WHERE id = %d", $this->ID), ARRAY_A); if ($getResult) { $row = $getResult[0]; $nameHash = "{$row['name']}_{$row['hash']}"; $delResult = $wpdb->query($wpdb->prepare("DELETE FROM `{$tblName}` WHERE id = %d", $this->ID)); if ($delResult != 0) { $tmpPath = DUP_Settings::getSsdirTmpPath(); $ssdPath = DUP_Settings::getSsdirPath(); $archiveFile = $this->getArchiveFilename(); $wpConfigFile = "{$this->NameHash}_wp-config.txt"; //Perms @chmod($tmpPath."/{$archiveFile}", 0644); @chmod($tmpPath."/{$nameHash}_database.sql", 0644); @chmod($tmpPath."/{$nameHash}_installer.php", 0644); @chmod($tmpPath."/{$nameHash}_scan.json", 0644); @chmod($tmpPath."/{$wpConfigFile}", 0644); @chmod($tmpPath."/{$nameHash}.log", 0644); @chmod($ssdPath."/{$archiveFile}", 0644); @chmod($ssdPath."/{$nameHash}_database.sql", 0644); @chmod($ssdPath."/{$nameHash}_installer.php", 0644); @chmod($ssdPath."/{$nameHash}_scan.json", 0644); // In older version, The plugin was storing [HASH]_wp-config.txt in main storage area. The below line code is for backward compatibility @chmod($ssdPath."/{$wpConfigFile}", 0644); @chmod($ssdPath."/{$nameHash}.log", 0644); //Remove @unlink($tmpPath."/{$archiveFile}"); @unlink($tmpPath."/{$nameHash}_database.sql"); @unlink($tmpPath."/{$nameHash}_installer.php"); @unlink($tmpPath."/{$nameHash}_scan.json"); @unlink($tmpPath."/{$wpConfigFile}"); @unlink($tmpPath."/{$nameHash}.log"); @unlink($ssdPath."/{$archiveFile}"); @unlink($ssdPath."/{$nameHash}_database.sql"); @unlink($ssdPath."/{$nameHash}_installer.php"); @unlink($ssdPath."/{$nameHash}_scan.json"); // In older version, The plugin was storing [HASH]_wp-config.txt in main storage area. The below line code is for backward compatibility @unlink($ssdPath."/{$wpConfigFile}"); @unlink($ssdPath."/{$nameHash}.log"); } } } /** * Get package archive size. * If package isn't complete it get size from sum of temp files. * * @return int size in byte */ public function getArchiveSize() { $size = 0; if ($this->Status >= DUP_PackageStatus::COMPLETE) { $size = $this->Archive->Size; } else { $tmpSearch = glob(DUP_Settings::getSsdirTmpPath() . "/{$this->NameHash}_*"); if (is_array($tmpSearch)) { $result = array_map('filesize', $tmpSearch); $size = array_sum($result); } } return $size; } /** * Return true if active package exist and have an active status * * @return bool */ public static function is_active_package_present() { $activePakcs = self::get_ids_by_status(array( array('op' => '>=', 'status' => DUP_PackageStatus::CREATED), array('op' => '<', 'status' => DUP_PackageStatus::COMPLETE) ), true); return in_array(DUP_Settings::Get('active_package_id'), $activePakcs); } /** * * @param array $conditions es. [ * relation = 'AND', * [ 'op' => '>=' , * 'status' => DUP_PackageStatus::START ] * [ 'op' => '<' , * 'status' => DUP_PackageStatus::COMPLETED ] * ] * @return string */ protected static function statusContitionsToWhere($conditions = array()) { if (empty($conditions)) { return ''; } else { $accepted_op = array('<', '>', '=', '<>', '>=', '<='); $relation = (isset($conditions['relation']) && strtoupper($conditions['relation']) == 'OR') ? ' OR ' : ' AND '; unset($conditions['relation']); $str_conds = array(); foreach ($conditions as $cond) { $op = (isset($cond['op']) && in_array($cond['op'], $accepted_op)) ? $cond['op'] : '='; $status = isset($cond['status']) ? (int) $cond['status'] : 0; $str_conds[] = 'status '.$op.' '.$status; } return ' WHERE '.implode($relation, $str_conds).' '; } } /** * Get packages with status conditions and/or pagination * * @global wpdb $wpdb * * @param array // $conditions es. [ * relation = 'AND', * [ 'op' => '>=' , * 'status' => DUP_PackageStatus::START ] * [ 'op' => '<' , * 'status' => DUP_PackageStatus::COMPLETED ] * ] * if empty get all pacages * @param int $limit // max row numbers fi false the limit is PHP_INT_MAX * @param int $offset // offset 0 is at begin * @param string $orderBy // default `id` ASC if empty no order * @param string $resultType // ids => int[] * row => row without backage blob * fullRow => row with package blob * objs => array of DUP_Package objects * * @return DUP_Package[]|array[]|int[] */ public static function get_packages_by_status($conditions = array(), $limit = false, $offset = 0, $orderBy = '`id` ASC', $resultType = 'obj') { global $wpdb; $table = $wpdb->base_prefix."duplicator_packages"; $where = self::statusContitionsToWhere($conditions); $packages = array(); $offsetStr = ' OFFSET '.(int) $offset; $limitStr = ' LIMIT '.($limit !== false ? max(0, $limit) : PHP_INT_MAX); $orderByStr = empty($orderBy) ? '' : ' ORDER BY '.$orderBy.' '; switch ($resultType) { case 'ids': $cols = '`id`'; break; case 'row': $cols = '`id`,`name`,`hash`,`status`,`created`,`owner`'; break; case 'fullRow': $cols = '*'; break; case 'objs': default: $cols = '`status`,`package`'; break; } $rows = $wpdb->get_results('SELECT '.$cols.' FROM `'.$table.'` '.$where.$orderByStr.$limitStr.$offsetStr); if ($rows != null) { switch ($resultType) { case 'ids': foreach ($rows as $row) { $packages[] = $row->id; } break; case 'row': case 'fullRow': $packages = $rows; break; case 'objs': default: foreach ($rows as $row) { $Package = unserialize($row->package); if ($Package) { // We was not storing Status in Lite 1.2.52, so it is for backward compatibility if (!isset($Package->Status)) { $Package->Status = $row->status; } $packages[] = $Package; } } } } return $packages; } /** * Get packages row db with status conditions and/or pagination * * @param array // $conditions es. [ * relation = 'AND', * [ 'op' => '>=' , * 'status' => DUP_PackageStatus::START ] * [ 'op' => '<' , * 'status' => DUP_PackageStatus::COMPLETED ] * ] * if empty get all pacages * @param int $limit // max row numbers * @param int $offset // offset 0 is at begin * @param string $orderBy // default `id` ASC if empty no order * * @return array[] // return row database without package blob */ public static function get_row_by_status($conditions = array(), $limit = false, $offset = 0, $orderBy = '`id` ASC') { return self::get_packages_by_status($conditions, $limit, $offset, $orderBy, 'row'); } /** * Get packages ids with status conditions and/or pagination * * @param array // $conditions es. [ * relation = 'AND', * [ 'op' => '>=' , * 'status' => DUP_PackageStatus::START ] * [ 'op' => '<' , * 'status' => DUP_PackageStatus::COMPLETED ] * ] * if empty get all pacages * @param int $limit // max row numbers * @param int $offset // offset 0 is at begin * @param string $orderBy // default `id` ASC if empty no order * * @return array[] // return row database without package blob */ public static function get_ids_by_status($conditions = array(), $limit = false, $offset = 0, $orderBy = '`id` ASC') { return self::get_packages_by_status($conditions, $limit, $offset, $orderBy, 'ids'); } /** * count package with status condition * * @global wpdb $wpdb * @param array $conditions es. [ * relation = 'AND', * [ 'op' => '>=' , * 'status' => DUP_PackageStatus::START ] * [ 'op' => '<' , * 'status' => DUP_PackageStatus::COMPLETED ] * ] * @return int */ public static function count_by_status($conditions = array()) { global $wpdb; $table = $wpdb->base_prefix."duplicator_packages"; $where = self::statusContitionsToWhere($conditions); $count = $wpdb->get_var("SELECT count(id) FROM `{$table}` ".$where); return $count; } /** * Execute $callback function foreach package result * For each iteration the memory is released * * @param callable $callback // function callback(DUP_Package $package) * @param array // $conditions es. [ * relation = 'AND', * [ 'op' => '>=' , * 'status' => DUP_PackageStatus::START ] * [ 'op' => '<' , * 'status' => DUP_PackageStatus::COMPLETED ] * ] * if empty get all pacages * @param int $limit // max row numbers * @param int $offset // offset 0 is at begin * @param string $orderBy // default `id` ASC if empty no order * * @return void */ public static function by_status_callback($callback, $conditions = array(), $limit = false, $offset = 0, $orderBy = '`id` ASC') { if (!is_callable($callback)) { throw new Exception('No callback function passed'); } $offset = max(0, $offset); $numPackages = self::count_by_status($conditions); $maxLimit = $offset + ($limit !== false ? max(0, $limit) : PHP_INT_MAX - $offset); $numPackages = min($maxLimit, $numPackages); $orderByStr = empty($orderBy) ? '' : ' ORDER BY '.$orderBy.' '; global $wpdb; $table = $wpdb->base_prefix."duplicator_packages"; $where = self::statusContitionsToWhere($conditions); $sql = 'SELECT * FROM `'.$table.'` '.$where.$orderByStr.' LIMIT 1 OFFSET '; for (; $offset < $numPackages; $offset ++) { $rows = $wpdb->get_results($sql.$offset); if ($rows != null) { $Package = @unserialize($rows[0]->package); if ($Package) { if (empty($Package->ID)) { $Package->ID = $rows[0]->id; } // We was not storing Status in Lite 1.2.52, so it is for backward compatibility if (!isset($Package->Status)) { $Package->Status = $rows[0]->status; } call_user_func($callback, $Package); unset($Package); } unset($rows); } } } public static function purge_incomplete_package() { $packages = self::get_packages_by_status(array( 'relation' => 'AND', array('op' => '>=', 'status' => DUP_PackageStatus::CREATED), array('op' => '<', 'status' => DUP_PackageStatus::COMPLETE) ), 1, 0, '`id` ASC'); if (count($packages) > 0) { foreach ($packages as $package) { if (!$package->isRunning()) { $package->delete(); } } } } /** * Check the DupArchive build to make sure it is good * * @return void */ public function runDupArchiveBuildIntegrityCheck() { //INTEGRITY CHECKS //We should not rely on data set in the serlized object, we need to manually check each value //indepentantly to have a true integrity check. DUP_Log::info("\n********************************************************************************"); DUP_Log::info("INTEGRITY CHECKS:"); DUP_Log::info("********************************************************************************"); //------------------------ //SQL CHECK: File should be at minimum 5K. A base WP install with only Create tables is about 9K $sql_temp_path = DUP_Settings::getSsdirTmpPath() . '/' . $this->Database->File; $sql_temp_size = @filesize($sql_temp_path); $sql_easy_size = DUP_Util::byteSize($sql_temp_size); $sql_done_txt = DUP_Util::tailFile($sql_temp_path, 3); DUP_Log::Trace('[DUP ARCHIVE] '.__FUNCTION__.' '.__LINE__); // Note: Had to add extra size check of 800 since observed bad sql when filter was on if (!strstr($sql_done_txt, 'DUPLICATOR_MYSQLDUMP_EOF') || (!$this->Database->FilterOn && $sql_temp_size < 5120) || ($this->Database->FilterOn && $this->Database->info->tablesFinalCount > 0 && $sql_temp_size < 800)) { DUP_Log::Trace('[DUP ARCHIVE] '.__FUNCTION__.' '.__LINE__); $error_text = "ERROR: SQL file not complete. The file {$sql_temp_path} looks too small ($sql_temp_size bytes) or the end of file marker was not found."; $this->BuildProgress->set_failed($error_text); $this->setStatus(DUP_PackageStatus::ERROR); DUP_Log::error("$error_text", '', Dup_ErrorBehavior::LogOnly); return; } DUP_Log::Trace('[DUP ARCHIVE] '.__FUNCTION__.' '.__LINE__); DUP_Log::Info("SQL FILE: {$sql_easy_size}"); //------------------------ //INSTALLER CHECK: $exe_temp_path = DUP_Settings::getSsdirTmpPath() . '/' . $this->Installer->File; $exe_temp_size = @filesize($exe_temp_path); $exe_easy_size = DUP_Util::byteSize($exe_temp_size); $exe_done_txt = DUP_Util::tailFile($exe_temp_path, 10); if (!strstr($exe_done_txt, 'DUPLICATOR_INSTALLER_EOF') && !$this->BuildProgress->failed) { //$this->BuildProgress->failed = true; $error_message = 'ERROR: Installer file not complete. The end of file marker was not found. Please try to re-create the package.'; $this->BuildProgress->set_failed($error_message); $this->Status = DUP_PackageStatus::ERROR; $this->update(); DUP_Log::error($error_message, '', Dup_ErrorBehavior::LogOnly); return; } DUP_Log::info("INSTALLER FILE: {$exe_easy_size}"); //------------------------ //ARCHIVE CHECK: DUP_LOG::trace("Archive file count is " . $this->Archive->file_count); if ($this->Archive->file_count != -1) { $zip_easy_size = DUP_Util::byteSize($this->Archive->Size); if (!($this->Archive->Size)) { //$this->BuildProgress->failed = true; $error_message = "ERROR: The archive file contains no size."; $this->BuildProgress->set_failed($error_message); $this->setStatus(DUP_PackageStatus::ERROR); DUP_Log::error($error_message, "Archive Size: {$zip_easy_size}", Dup_ErrorBehavior::LogOnly); return; } $scan_filepath = DUP_Settings::getSsdirTmpPath() . "/{$this->NameHash}_scan.json"; $json = ''; DUP_LOG::Trace("***********Does $scan_filepath exist?"); if (file_exists($scan_filepath)) { $json = file_get_contents($scan_filepath); } else { $error_message = sprintf(__("Can't find Scanfile %s. Please ensure there no non-English characters in the package or schedule name.", 'duplicator'), $scan_filepath); //$this->BuildProgress->failed = true; //$this->setStatus(DUP_PackageStatus::ERROR); $this->BuildProgress->set_failed($error_message); $this->setStatus(DUP_PackageStatus::ERROR); DUP_Log::error($error_message, '', Dup_ErrorBehavior::LogOnly); return; } $scanReport = json_decode($json); //RSR TODO: rework/simplify the validateion of duparchive $dirCount = count($scanReport->ARC->Dirs); $numInstallerDirs = $this->Installer->numDirsAdded; $fileCount = count($scanReport->ARC->Files); $numInstallerFiles = $this->Installer->numFilesAdded; $expected_filecount = $dirCount + $numInstallerDirs + $fileCount + $numInstallerFiles + 1 -1; // Adding database.sql but subtracting the root dir //Dup_Log::trace("#### a:{$dirCount} b:{$numInstallerDirs} c:{$fileCount} d:{$numInstallerFiles} = {$expected_filecount}"); DUP_Log::info("ARCHIVE FILE: {$zip_easy_size} "); DUP_Log::info(sprintf(__('EXPECTED FILE/DIRECTORY COUNT: %1$s', 'duplicator'), number_format($expected_filecount))); DUP_Log::info(sprintf(__('ACTUAL FILE/DIRECTORY COUNT: %1$s', 'duplicator'), number_format($this->Archive->file_count))); $this->ExeSize = $exe_easy_size; $this->ZipSize = $zip_easy_size; /* ------- ZIP Filecount Check -------- */ // Any zip of over 500 files should be within 2% - this is probably too loose but it will catch gross errors DUP_LOG::trace("Expected filecount = $expected_filecount and archive filecount=" . $this->Archive->file_count); if ($expected_filecount > 500) { $straight_ratio = (float) $expected_filecount / (float) $this->Archive->file_count; $warning_count = $scanReport->ARC->WarnFileCount + $scanReport->ARC->WarnDirCount + $scanReport->ARC->UnreadableFileCount + $scanReport->ARC->UnreadableDirCount; DUP_LOG::trace("Warn/unread counts) warnfile:{$scanReport->ARC->WarnFileCount} warndir:{$scanReport->ARC->WarnDirCount} unreadfile:{$scanReport->ARC->UnreadableFileCount} unreaddir:{$scanReport->ARC->UnreadableDirCount}"); $warning_ratio = ((float) ($expected_filecount + $warning_count)) / (float) $this->Archive->file_count; DUP_LOG::trace("Straight ratio is $straight_ratio and warning ratio is $warning_ratio. # Expected=$expected_filecount # Warning=$warning_count and #Archive File {$this->Archive->file_count}"); // Allow the real file count to exceed the expected by 10% but only allow 1% the other way if (($straight_ratio < 0.90) || ($straight_ratio > 1.01)) { // Has to exceed both the straight as well as the warning ratios if (($warning_ratio < 0.90) || ($warning_ratio > 1.01)) { $error_message = sprintf('ERROR: File count in archive vs expected suggests a bad archive (%1$d vs %2$d).', $this->Archive->file_count, $expected_filecount); $this->BuildProgress->set_failed($error_message); $this->Status = DUP_PackageStatus::ERROR; $this->update(); DUP_Log::error($error_message, ''); return; } } } } /* ------ ZIP CONSISTENCY CHECK ------ */ if ($this->Archive->getBuildMode() == DUP_Archive_Build_Mode::ZipArchive) { DUP_LOG::trace("Running ZipArchive consistency check"); $zipPath = DUP_Settings::getSsdirTmpPath()."/{$this->Archive->File}"; $zip = new ZipArchive(); // ZipArchive::CHECKCONS will enforce additional consistency checks $res = $zip->open($zipPath, ZipArchive::CHECKCONS); if ($res !== TRUE) { $consistency_error = sprintf(__('ERROR: Cannot open created archive. Error code = %1$s', 'duplicator'), $res); DUP_LOG::trace($consistency_error); switch ($res) { case ZipArchive::ER_NOZIP : $consistency_error = __('ERROR: Archive is not valid zip archive.', 'duplicator'); break; case ZipArchive::ER_INCONS : $consistency_error = __("ERROR: Archive doesn't pass consistency check.", 'duplicator'); break; case ZipArchive::ER_CRC : $consistency_error = __("ERROR: Archive checksum is bad.", 'duplicator'); break; } $this->BuildProgress->set_failed($consistency_error); $this->Status = DUP_PackageStatus::ERROR; $this->update(); DUP_LOG::trace($consistency_error); DUP_Log::error($consistency_error, ''); } else { DUP_Log::info(__('ARCHIVE CONSISTENCY TEST: Pass', 'duplicator')); DUP_LOG::trace("Zip for package $this->ID passed consistency test"); } $zip->close(); } } public function getLocalPackageFile($file_type) { $file_path = null; if ($file_type == DUP_PackageFileType::Installer) { DUP_Log::Trace("Installer requested"); $file_name = apply_filters('duplicator_installer_file_path', $this->getInstallerFilename()); } else if ($file_type == DUP_PackageFileType::Archive) { DUP_Log::Trace("Archive requested"); $file_name = $this->getArchiveFilename(); } else if ($file_type == DUP_PackageFileType::SQL) { DUP_Log::Trace("SQL requested"); $file_name = $this->getDatabaseFilename(); } else { DUP_Log::Trace("Log requested"); $file_name = $this->getLogFilename(); } $file_path = DUP_Settings::getSsdirPath() . "/$file_name"; DUP_Log::Trace("File path $file_path"); if (file_exists($file_path)) { return $file_path; } else { return null; } } public function getScanFilename() { return $this->NameHash . '_scan.json'; } public function getScanUrl() { return DUP_Settings::getSsdirUrl()."/".$this->getScanFilename(); } public function getLogFilename() { return $this->NameHash . '.log'; } public function getLogUrl() { return DUP_Settings::getSsdirUrl()."/".$this->getLogFilename(); } public function getArchiveFilename() { $extension = strtolower($this->Archive->Format); return "{$this->NameHash}_archive.{$extension}"; } public function getInstallerFilename() { return "{$this->NameHash}_installer.php"; } public function getDatabaseFilename() { return $this->NameHash . '_database.sql'; } /** * @param int $type * @return array */ public function getPackageFileDownloadInfo($type) { $result = array( "filename" => "", "url" => "" ); switch ($type){ case DUP_PackageFileType::Archive; $result["filename"] = $this->Archive->File; $result["url"] = $this->Archive->getURL(); break; case DUP_PackageFileType::SQL; $result["filename"] = $this->Database->File; $result["url"] = $this->Database->getURL(); break; case DUP_PackageFileType::Log; $result["filename"] = $this->getLogFilename(); $result["url"] = $this->getLogUrl(); break; case DUP_PackageFileType::Scan; $result["filename"] = $this->getScanFilename(); $result["url"] = $this->getScanUrl(); break; default: break; } return $result; } public function getInstallerDownloadInfo() { return array( "id" => $this->ID, "hash" => $this->Hash ); } /** * Removes all files except those of active packages */ public static function not_active_files_tmp_cleanup() { //Check for the 'tmp' folder just for safe measures if (! is_dir(DUP_Settings::getSsdirTmpPath()) && (strpos(DUP_Settings::getSsdirTmpPath(), 'tmp') !== false) ) { return; } $globs = glob(DUP_Settings::getSsdirTmpPath().'/*.*'); if (! is_array($globs) || $globs === FALSE) { return; } // RUNNING PACKAGES $active_pack = self::get_row_by_status(array( 'relation' => 'AND', array('op' => '>=' , 'status' => DUP_PackageStatus::CREATED ), array('op' => '<' , 'status' => DUP_PackageStatus::COMPLETE ) )); $active_files = array(); foreach($active_pack as $row) { $active_files[] = $row->name.'_'.$row->hash; } // ERRORS PACKAGES $err_pack = self::get_row_by_status(array( array('op' => '<' , 'status' => DUP_PackageStatus::CREATED ) )); $force_del_files = array(); foreach($err_pack as $row) { $force_del_files[] = $row->name.'_'.$row->hash; } // Don't remove json file; $extension_filter = array('json'); // Calculate delta time for old files $oldTimeToClean = time() - DUPLICATOR_TEMP_CLEANUP_SECONDS; foreach ($globs as $glob_full_path) { // Don't remove sub dir if (is_dir($glob_full_path)) { continue; } $file_name = basename($glob_full_path); // skip all active packages foreach ($active_files as $c_nameHash) { if (strpos($file_name, $c_nameHash) === 0) { continue 2; } } // Remove all old files if (filemtime($glob_full_path) <= $oldTimeToClean) { @unlink($glob_full_path); continue; } // remove all error packages files foreach ($force_del_files as $c_nameHash) { if (strpos($file_name, $c_nameHash) === 0) { @unlink($glob_full_path); continue 2; } } $file_info = pathinfo($glob_full_path); // skip json file for pre build packages if (in_array($file_info['extension'], $extension_filter) || in_array($file_name, $active_files)) { continue; } @unlink($glob_full_path); } } /** * Cleans up the temp storage folder have a time interval * * @return void */ public static function safeTmpCleanup($purge_temp_archives = false) { if ($purge_temp_archives) { $dir = DUP_Settings::getSsdirTmpPath() . "/*_archive.zip.*"; foreach (glob($dir) as $file_path) { unlink($file_path); } $dir = DUP_Settings::getSsdirTmpPath() . "/*_archive.daf.*"; foreach (glob($dir) as $file_path) { unlink($file_path); } } else { //Remove all temp files that are 24 hours old $dir = DUP_Settings::getSsdirTmpPath() . "/*"; $files = glob($dir); if ($files !== false) { foreach ($files as $file_path) { // Cut back to keeping things around for just an hour 15 min if (filemtime($file_path) <= time() - DUPLICATOR_TEMP_CLEANUP_SECONDS) { unlink($file_path); } } } } } /** * Starts the package DupArchive progressive build process - always assumed to only run off active package, NOT one in the package table * * @return obj Returns a DUP_Package object */ public function runDupArchiveBuild() { $this->BuildProgress->start_timer(); DUP_Log::Trace('Called'); if ($this->BuildProgress->failed) { DUP_LOG::Trace("build progress failed so setting package to failed"); $this->setStatus(DUP_PackageStatus::ERROR); $message = "Package creation failed."; DUP_Log::Trace($message); return true; } if ($this->BuildProgress->initialized == false) { DUP_Log::Trace('[DUP ARCHIVE] INIZIALIZE'); $this->BuildProgress->initialized = true; $this->TimerStart = Dup_Util::getMicrotime(); $this->update(); } //START BUILD if (!$this->BuildProgress->database_script_built) { DUP_Log::Info('[DUP ARCHIVE] BUILDING DATABASE'); $this->Database->build($this, Dup_ErrorBehavior::ThrowException); DUP_Log::Info('[DUP ARCHIVE] VALIDATING DATABASE'); $this->Database->validateTableWiseRowCounts(); $this->BuildProgress->database_script_built = true; $this->update(); DUP_Log::Info('[DUP ARCHIVE] DONE DATABASE'); } else if (!$this->BuildProgress->archive_built) { DUP_Log::Info('[DUP ARCHIVE] BUILDING ARCHIVE'); $this->Archive->build($this); $this->update(); DUP_Log::Info('[DUP ARCHIVE] DONE ARCHIVE'); } else if (!$this->BuildProgress->installer_built) { DUP_Log::Info('[DUP ARCHIVE] BUILDING INSTALLER'); // Installer being built is stuffed into the archive build phase } if ($this->BuildProgress->has_completed()) { DUP_Log::Info('[DUP ARCHIVE] HAS COMPLETED CLOSING'); if (!$this->BuildProgress->failed) { DUP_LOG::Info("[DUP ARCHIVE] DUP ARCHIVE INTEGRITY CHECK"); // Only makees sense to perform build integrity check on completed archives $this->runDupArchiveBuildIntegrityCheck(); } else { DUP_LOG::trace("top of loop build progress failed"); } $timerEnd = DUP_Util::getMicrotime(); $timerSum = DUP_Util::elapsedTime($timerEnd, $this->TimerStart); $this->Runtime = $timerSum; //FINAL REPORT $info = "\n********************************************************************************\n"; $info .= "RECORD ID:[{$this->ID}]\n"; $info .= "TOTAL PROCESS RUNTIME: {$timerSum}\n"; $info .= "PEAK PHP MEMORY USED: " . DUP_Server::getPHPMemory(true) . "\n"; $info .= "DONE PROCESSING => {$this->Name} " . @date("Y-m-d H:i:s") . "\n"; DUP_Log::info($info); DUP_LOG::trace("Done package building"); if (!$this->BuildProgress->failed) { DUP_Log::Trace('[DUP ARCHIVE] HAS COMPLETED DONE'); $this->setStatus(DUP_PackageStatus::COMPLETE); DUP_LOG::Trace("Cleaning up duparchive temp files"); //File Cleanup $this->buildCleanup(); do_action('duplicator_lite_build_completed' , $this); } else { DUP_Log::Trace('[DUP ARCHIVE] HAS COMPLETED ERROR'); } } DUP_Log::Close(); return $this->BuildProgress->has_completed(); } /** * Starts the package build process * * @return obj Returns a DUP_Package object */ public function runZipBuild() { $timerStart = DUP_Util::getMicrotime(); DUP_Log::Trace('#### start of zip build'); //START BUILD //PHPs serialze method will return the object, but the ID above is not passed //for one reason or another so passing the object back in seems to do the trick $this->Database->build($this, Dup_ErrorBehavior::ThrowException); $this->Database->validateTableWiseRowCounts(); $this->Archive->build($this); $this->Installer->build($this); //INTEGRITY CHECKS /*DUP_Log::Info("\n********************************************************************************"); DUP_Log::Info("INTEGRITY CHECKS:"); DUP_Log::Info("********************************************************************************");*/ $this->runDupArchiveBuildIntegrityCheck(); $dbSizeRead = DUP_Util::byteSize($this->Database->Size); $zipSizeRead = DUP_Util::byteSize($this->Archive->Size); $exeSizeRead = DUP_Util::byteSize($this->Installer->Size); $timerEnd = DUP_Util::getMicrotime(); $timerSum = DUP_Util::elapsedTime($timerEnd, $timerStart); $this->Runtime = $timerSum; $this->ExeSize = $exeSizeRead; $this->ZipSize = $zipSizeRead; $this->buildCleanup(); //FINAL REPORT $info = "\n********************************************************************************\n"; $info .= "RECORD ID:[{$this->ID}]\n"; $info .= "TOTAL PROCESS RUNTIME: {$timerSum}\n"; $info .= "PEAK PHP MEMORY USED: ".DUP_Server::getPHPMemory(true)."\n"; $info .= "DONE PROCESSING => {$this->Name} ".@date(get_option('date_format')." ".get_option('time_format'))."\n"; DUP_Log::Info($info); DUP_Log::Close(); $this->setStatus(DUP_PackageStatus::COMPLETE); return $this; } /** * Saves the active options associted with the active(latest) package. * * @see DUP_Package::getActive * * @param $_POST $post The Post server object * * @return null */ public function saveActive($post = null) { global $wp_version; if (isset($post)) { $post = stripslashes_deep($post); $name = isset($post['package-name']) ? trim($post['package-name']) : self::getDefaultName(); $name = str_replace(array(' ', '-'), '_', $name); $name = str_replace(array('.', ';', ':', "'", '"'), '', $name); $name = sanitize_file_name($name); $name = substr(trim($name), 0, 40); if (isset($post['filter-dirs'])) { $post_filter_dirs = sanitize_text_field($post['filter-dirs']); $filter_dirs = $this->Archive->parseDirectoryFilter($post_filter_dirs); } else { $filter_dirs = ''; } if (isset($post['filter-files'])) { $post_filter_files = sanitize_text_field($post['filter-files']); $filter_files = $this->Archive->parseFileFilter($post_filter_files); } else { $filter_files = ''; } if (isset($post['filter-exts'])) { $post_filter_exts = sanitize_text_field($post['filter-exts']); $filter_exts = $this->Archive->parseExtensionFilter($post_filter_exts); } else { $filter_exts = ''; } $tablelist = ''; if (isset($post['dbtables'])) { $tablelist = implode(',', $post['dbtables']); } if (isset($post['dbcompat'])) { $post_dbcompat = sanitize_text_field($post['dbcompat']); $compatlist = isset($post['dbcompat']) ? implode(',', $post_dbcompat) : ''; } else { $compatlist = ''; } $dbversion = DUP_DB::getVersion(); $dbversion = is_null($dbversion) ? '- unknown -' : sanitize_text_field($dbversion); $dbcomments = sanitize_text_field(DUP_DB::getVariable('version_comment')); $dbcomments = is_null($dbcomments) ? '- unknown -' : sanitize_text_field($dbcomments); //PACKAGE $this->Created = gmdate("Y-m-d H:i:s"); $this->Version = DUPLICATOR_VERSION; $this->VersionOS = defined('PHP_OS') ? PHP_OS : 'unknown'; $this->VersionWP = $wp_version; $this->VersionPHP = phpversion(); $this->VersionDB = sanitize_text_field($dbversion); $this->Name = sanitize_text_field($name); $this->Hash = $this->makeHash(); $this->NameHash = sanitize_text_field("{$this->Name}_{$this->Hash}"); $this->Notes = sanitize_textarea_field($post['package-notes']); //ARCHIVE $this->Archive->PackDir = duplicator_get_abs_path(); $this->Archive->Format = 'ZIP'; $this->Archive->FilterOn = isset($post['filter-on']) ? 1 : 0; $this->Archive->ExportOnlyDB = isset($post['export-onlydb']) ? 1 : 0; $this->Archive->FilterDirs = sanitize_textarea_field($filter_dirs); $this->Archive->FilterFiles = sanitize_textarea_field($filter_files); $this->Archive->FilterExts = str_replace(array('.', ' '), '', $filter_exts); //INSTALLER $this->Installer->OptsDBHost = sanitize_text_field($post['dbhost']); $this->Installer->OptsDBPort = sanitize_text_field($post['dbport']); $this->Installer->OptsDBName = sanitize_text_field($post['dbname']); $this->Installer->OptsDBUser = sanitize_text_field($post['dbuser']); $this->Installer->OptsDBCharset = sanitize_text_field($post['dbcharset']); $this->Installer->OptsDBCollation = sanitize_text_field($post['dbcollation']); $this->Installer->OptsSecureOn = isset($post['secure-on']) ? 1 : 0; $post_secure_pass = sanitize_text_field($post['secure-pass']); $this->Installer->OptsSecurePass = DUP_Util::installerScramble($post_secure_pass); //DATABASE $this->Database->FilterOn = isset($post['dbfilter-on']) ? 1 : 0; $this->Database->FilterTables = sanitize_text_field($tablelist); $this->Database->Compatible = $compatlist; $this->Database->Comments = sanitize_text_field($dbcomments); update_option(self::OPT_ACTIVE, $this); } } /** * Update the serialized package and status in the database * * @return void */ public function update() { global $wpdb; $this->Status = number_format($this->Status, 1, '.', ''); $this->cleanObjectBeforeSave(); $packageObj = serialize($this); if (!$packageObj) { DUP_Log::error("Package SetStatus was unable to serialize package object while updating record."); } $wpdb->flush(); $tablePrefix = DUP_Util::getTablePrefix(); $table = $tablePrefix."duplicator_packages"; $sql = "UPDATE `{$table}` SET status = {$this->Status},"; $sql .= "package = '" . esc_sql($packageObj) . "'"; $sql .= "WHERE ID = {$this->ID}"; DUP_Log::Trace("UPDATE PACKAGE ID = {$this->ID} STATUS = {$this->Status}"); //DUP_Log::Trace('####Executing SQL' . $sql . '-----------'); $wpdb->query($sql); } /** * Save any property of this class through reflection * * @param $property A valid public property in this class * @param $value The value for the new dynamic property * * @return null */ public function saveActiveItem($property, $value) { $package = self::getActive(); $reflectionClass = new ReflectionClass($package); $reflectionClass->getProperty($property)->setValue($package, $value); update_option(self::OPT_ACTIVE, $package); } /** * Sets the status to log the state of the build * The status level for where the package is * * @param int $status * * @return void */ public function setStatus($status) { if (!isset($status)) { DUP_Log::error("Package SetStatus did not receive a proper code."); } $this->Status = $status; $this->update(); } /** * Does a hash already exists * Returns 0 if no hash is found, if found returns the table ID * * @param string $hash An existing hash value * * @return int */ public function getHashKey($hash) { global $wpdb; $tablePrefix = DUP_Util::getTablePrefix(); $table = $tablePrefix."duplicator_packages"; $qry = $wpdb->get_row("SELECT ID, hash FROM `{$table}` WHERE hash = '{$hash}'"); if (is_null($qry) || strlen($qry->hash) == 0) { return 0; } else { return $qry->ID; } } /** * Makes the hashkey for the package files * * @return string // A unique hashkey */ public function makeHash() { try { if (function_exists('random_bytes') && DUP_Util::PHP53()) { return bin2hex(random_bytes(8)) . mt_rand(1000, 9999) . '_' . date("YmdHis"); } else { return strtolower(md5(uniqid(rand(), true))) . '_' . date("YmdHis"); } } catch (Exception $exc) { return strtolower(md5(uniqid(rand(), true))) . '_' . date("YmdHis"); } } /** * Gets the active package which is defined as the package that was lasted saved. * Do to cache issues with the built in WP function get_option moved call to a direct DB call. * * @see DUP_Package::saveActive * * @return DUP_Package // A copy of the DUP_Package object */ public static function getActive() { global $wpdb; $obj = new DUP_Package(); $row = $wpdb->get_row($wpdb->prepare("SELECT option_value FROM `{$wpdb->options}` WHERE option_name = %s LIMIT 1", self::OPT_ACTIVE)); if (is_object($row)) { $obj = @unserialize($row->option_value); } //Incase unserilaize fails $obj = (is_object($obj)) ? $obj : new DUP_Package(); return $obj; } /** * Gets the Package by ID * * @param int $id A valid package id form the duplicator_packages table * * @return DUP_Package // A copy of the DUP_Package object */ public static function getByID($id) { global $wpdb; $obj = new DUP_Package(); $tablePrefix = DUP_Util::getTablePrefix(); $sql = $wpdb->prepare("SELECT * FROM `{$tablePrefix}duplicator_packages` WHERE ID = %d", $id); $row = $wpdb->get_row($sql); if (is_object($row)) { $obj = @unserialize($row->package); // We was not storing Status in Lite 1.2.52, so it is for backward compatibility if (!isset($obj->Status)) { $obj->Status = $row->status; } } //Incase unserilaize fails $obj = (is_object($obj)) ? $obj : null; return $obj; } /** * Gets a default name for the package * * @return string // A default package name such as 20170218_blogname */ public static function getDefaultName($preDate = true) { //Remove specail_chars from final result $special_chars = array(".", "-"); $name = ($preDate) ? date('Ymd') . '_' . sanitize_title(get_bloginfo('name', 'display')) : sanitize_title(get_bloginfo('name', 'display')) . '_' . date('Ymd'); $name = substr(sanitize_file_name($name), 0, 40); $name = str_replace($special_chars, '', $name); return $name; } /** * Cleanup all tmp files * * @param all empty all contents * * @return null */ public static function tempFileCleanup($all = false) { //Delete all files now if ($all) { $dir = DUP_Settings::getSsdirTmpPath()."/*"; foreach (glob($dir) as $file) { @unlink($file); } } //Remove scan files that are 24 hours old else { $dir = DUP_Settings::getSsdirTmpPath()."/*_scan.json"; foreach (glob($dir) as $file) { if (filemtime($file) <= time() - 86400) { @unlink($file); } } } } /** * Provides various date formats * * @param $utcDate created date in the GMT timezone * @param $format Various date formats to apply * * @return string // a formated date based on the $format */ public static function getCreatedDateFormat($utcDate, $format = 1) { $date = get_date_from_gmt($utcDate); $date = new DateTime($date); switch ($format) { //YEAR case 1: return $date->format('Y-m-d H:i'); break; case 2: return $date->format('Y-m-d H:i:s'); break; case 3: return $date->format('y-m-d H:i'); break; case 4: return $date->format('y-m-d H:i:s'); break; //MONTH case 5: return $date->format('m-d-Y H:i'); break; case 6: return $date->format('m-d-Y H:i:s'); break; case 7: return $date->format('m-d-y H:i'); break; case 8: return $date->format('m-d-y H:i:s'); break; //DAY case 9: return $date->format('d-m-Y H:i'); break; case 10: return $date->format('d-m-Y H:i:s'); break; case 11: return $date->format('d-m-y H:i'); break; case 12: return $date->format('d-m-y H:i:s'); break; default : return $date->format('Y-m-d H:i'); } } /** * Cleans up all the tmp files as part of the package build process */ public function buildCleanup() { $files = DUP_Util::listFiles(DUP_Settings::getSsdirTmpPath()); $newPath = DUP_Settings::getSsdirPath(); $filesToStore = array( $this->Installer->File, $this->Archive->File, ); foreach ($files as $file) { $fileName = basename($file); if (!strstr($fileName, $this->NameHash)) { continue; } if (in_array($fileName, $filesToStore)) { if (function_exists('rename')) { rename($file, "{$newPath}/{$fileName}"); } elseif (function_exists('copy')) { copy($file, "{$newPath}/{$fileName}"); } else { throw new Exception('PHP copy and rename functions not found! Contact hosting provider!'); } } if (file_exists($file)) { unlink($file); } } } /** * Get package hash * * @return string package hash */ public function getPackageHash() { $hashParts = explode('_', $this->Hash); $firstPart = substr($hashParts[0], 0, 7); $secondPart = substr($hashParts[1], -8); $package_hash = $firstPart.'-'.$secondPart; return $package_hash; } public function getSecondaryPackageHash() { $newHash = $this->makeHash(); $hashParts = explode('_', $newHash); $firstPart = substr($hashParts[0], 0, 7); $hashParts = explode('_', $this->Hash); $secondPart = substr($hashParts[1], -8); $package_hash = $firstPart.'-'.$secondPart; return $package_hash; } /** * Provides the full sql file path in archive * * @return the full sql file path in archive */ public function getSqlArkFilePath() { $package_hash = $this->getPackageHash(); $sql_ark_file_Path = 'dup-installer/dup-database__'.$package_hash.'.sql'; return $sql_ark_file_Path; } private function writeLogHeader() { $php_max_time = @ini_get("max_execution_time"); if (DupLiteSnapLibUtil::wp_is_ini_value_changeable('memory_limit')) $php_max_memory = @ini_set('memory_limit', DUPLICATOR_PHP_MAX_MEMORY); else $php_max_memory = @ini_get('memory_limit'); $php_max_time = ($php_max_time == 0) ? "(0) no time limit imposed" : "[{$php_max_time}] not allowed"; $php_max_memory = ($php_max_memory === false) ? "Unabled to set php memory_limit" : DUPLICATOR_PHP_MAX_MEMORY." ({$php_max_memory} default)"; $info = "********************************************************************************\n"; $info .= "DUPLICATOR-LITE PACKAGE-LOG: ".@date(get_option('date_format')." ".get_option('time_format'))."\n"; $info .= "NOTICE: Do NOT post to public sites or forums \n"; $info .= "********************************************************************************\n"; $info .= "VERSION:\t".DUPLICATOR_VERSION."\n"; $info .= "WORDPRESS:\t{$GLOBALS['wp_version']}\n"; $info .= "PHP INFO:\t".phpversion().' | '.'SAPI: '.php_sapi_name()."\n"; $info .= "SERVER:\t\t{$_SERVER['SERVER_SOFTWARE']} \n"; $info .= "PHP TIME LIMIT: {$php_max_time} \n"; $info .= "PHP MAX MEMORY: {$php_max_memory} \n"; $info .= "MEMORY STACK: ".DUP_Server::getPHPMemory(); DUP_Log::Info($info); $info = null; } } class.io.php 0000644 00000005040 15133151516 0006770 0 ustar 00 <?php defined('ABSPATH') || defined('DUPXABSPATH') || exit; /** * @copyright 2018 Snap Creek LLC * Class for all IO operations */ // Exit if accessed directly if (! defined('DUPLICATOR_VERSION')) exit; class DUP_IO { /** * Safely deletes a file * * @param string $file The full filepath to the file * * @return TRUE on success or if file does not exist. FALSE on failure */ public static function deleteFile($file) { if (file_exists($file)) { if (@unlink($file) === false) { DUP_Log::Info("Could not delete file: {$file}"); return false; } } return true; } /** * Removes a directory recursively except for the root of a WP Site * * @param string $directory The full filepath to the directory to remove * * @return TRUE on success FALSE on failure */ public static function deleteTree($directory) { $success = true; if(!file_exists("{$directory}/wp-config.php")) { $filenames = array_diff(scandir($directory), array('.', '..')); foreach ($filenames as $filename) { if (is_dir("$directory/$filename")) { $success = self::deleteTree("$directory/$filename"); } else { $success = @unlink("$directory/$filename"); } if ($success === false) { break; } } } else { return false; } return $success && @rmdir($directory); } /** * Safely copies a file to a directory * * @param string $source_file The full filepath to the file to copy * @param string $dest_dir The full path to the destination directory were the file will be copied * @param string $delete_first Delete file before copying the new one * * @return TRUE on success or if file does not exist. FALSE on failure */ public static function copyFile($source_file, $dest_dir, $delete_first = false) { //Create directory if (file_exists($dest_dir) == false) { if (wp_mkdir_p($dest_dir) === false) { return false; } } //Remove file with same name before copy $filename = basename($source_file); $dest_filepath = $dest_dir . "/$filename"; if($delete_first) { self::deleteFile($dest_filepath); } return copy($source_file, $dest_filepath); } } class.archive.config.php 0000644 00000002041 15133151516 0011244 0 ustar 00 <?php defined('ABSPATH') || defined('DUPXABSPATH') || exit; /** * @copyright 2016 Snap Creek LLC */ // Exit if accessed directly if (! defined('DUPLICATOR_VERSION')) exit; class DUP_Archive_Config { //READ-ONLY: COMPARE VALUES public $created; public $version_dup; public $version_wp; public $version_db; public $version_php; public $version_os; public $dbInfo; //READ-ONLY: GENERAL public $url_old; public $opts_delete; public $blogname; public $wproot; public $wplogin_url; public $relative_content_dir; public $exportOnlyDB; public $installSiteOverwriteOn; //PRE-FILLED: GENERAL public $secure_on; public $secure_pass; public $skipscan; public $dbhost; public $dbname; public $dbuser; public $dbpass; public $dbcharset; public $dbcollation; // MULTISITE public $mu_mode; public $wp_tableprefix; public $is_outer_root_wp_config_file; public $is_outer_root_wp_content_dir; } class.constants.php 0000644 00000000226 15133151516 0010376 0 ustar 00 <?php defined("ABSPATH") || exit; class DUP_Constants { const ZIP_STRING_LIMIT = 70000; // Cutoff for using ZipArchive addtostring vs addfile } index.php 0000644 00000000016 15133151516 0006362 0 ustar 00 <?php //silent host/class.liquidweb.host.php 0000644 00000001145 15133151516 0012301 0 ustar 00 <?php /** * wpengine custom hosting class * * Standard: PSR-2 * * @package SC\DUPX\HOST * @link http://www.php-fig.org/psr/psr-2/ * */ defined('ABSPATH') || defined('DUPXABSPATH') || exit; class DUP_Liquidweb_Host implements DUP_Host_interface { public static function getIdentifier() { return DUP_Custom_Host_Manager::HOST_LIQUIDWEB; } public function isHosting() { return apply_filters('duplicator_liquidweb_host_check', file_exists(DupLiteSnapLibIOU::safePathUntrailingslashit(WPMU_PLUGIN_DIR).'/liquid-web.php')); } public function init() { } } host/class.wpengine.host.php 0000644 00000002617 15133151516 0012135 0 ustar 00 <?php defined("ABSPATH") or die(""); // New encryption class class DUP_WPEngine_Host implements DUP_Host_interface { public function init() { add_filter('duplicator_installer_file_path', array(__CLASS__, 'installerFilePath'), 10, 1); add_filter('duplicator_global_file_filters_on', '__return_true'); add_filter('duplicator_global_file_filters', array(__CLASS__, 'globalFileFilters'), 10, 1); add_filter('duplicator_defaults_settings', array(__CLASS__, 'defaultsSettings')); } public static function getIdentifier() { return DUP_Custom_Host_Manager::HOST_WPENGINE; } public function isHosting() { return apply_filters('duplicator_wp_engine_host_check', file_exists(DupLiteSnapLibIOU::safePathUntrailingslashit(WPMU_PLUGIN_DIR).'/wpengine-security-auditor.php')); } public static function installerFilePath($path) { $path_info = pathinfo($path); $newPath = $path; if ('php' == $path_info['extension']) { $newPath = substr_replace($path, '.txt', -4); } return $newPath; } public static function globalFileFilters($files) { $files[] = wp_normalize_path(WP_CONTENT_DIR).'/mysql.sql'; return $files; } public static function defaultsSettings($defaults) { $defaults['package_zip_flush'] = '1'; return $defaults; } } host/interface.host.php 0000644 00000001135 15133151516 0011147 0 ustar 00 <?php /** * interface for specific hostings class * * Standard: PSR-2 * * @package SC\DUPX\HOST * @link http://www.php-fig.org/psr/psr-2/ * */ defined('ABSPATH') || defined('DUPXABSPATH') || exit; interface DUP_Host_interface { /** * return the current host itentifier * * @return string */ public static function getIdentifier(); /** * @return bool true if is current host */ public function isHosting(); /** * the init function. * is called only if isHosting is true * * @return void */ public function init(); } host/class.wordpresscom.host.php 0000644 00000001162 15133151516 0013042 0 ustar 00 <?php /** * godaddy custom hosting class * * Standard: PSR-2 * * @package SC\DUPX\HOST * @link http://www.php-fig.org/psr/psr-2/ * */ defined('ABSPATH') || defined('DUPXABSPATH') || exit; class DUP_WordpressCom_Host implements DUP_Host_interface { public static function getIdentifier() { return DUP_Custom_Host_Manager::HOST_WORDPRESSCOM; } public function isHosting() { return apply_filters('duplicator_pro_wordpress_host_check', file_exists(DupLiteSnapLibIOU::safePathUntrailingslashit(WPMU_PLUGIN_DIR).'/wpcomsh-loader.php')); } public function init() { } } host/class.flywheel.host.php 0000644 00000001146 15133151516 0012134 0 ustar 00 <?php /** * Flywheel custom hosting class * * Standard: PSR-2 * * @package SC\DUPX\HOST * @link http://www.php-fig.org/psr/psr-2/ * */ defined('ABSPATH') || defined('DUPXABSPATH') || exit; class DUP_Flywheel_Host implements DUP_Host_interface { public static function getIdentifier() { return DUP_Custom_Host_Manager::HOST_FLYWHEEL; } public function isHosting() { $path = duplicator_get_home_path().'/.fw-config.php'; return apply_filters('duplicator_host_check', file_exists($path), self::getIdentifier()); } public function init() { } } host/class.custom.host.manager.php 0000644 00000011032 15133151516 0013233 0 ustar 00 <?php /** * custom hosting manager * singleton class * * Standard: PSR-2 * * @package SC\DUPX\HOST * @link http://www.php-fig.org/psr/psr-2/ * */ defined('ABSPATH') || defined('DUPXABSPATH') || exit; require_once (DUPLICATOR_PLUGIN_PATH . '/classes/host/interface.host.php'); require_once (DUPLICATOR_PLUGIN_PATH . '/classes/host/class.godaddy.host.php'); require_once (DUPLICATOR_PLUGIN_PATH . '/classes/host/class.wpengine.host.php'); require_once (DUPLICATOR_PLUGIN_PATH . '/classes/host/class.wordpresscom.host.php'); require_once (DUPLICATOR_PLUGIN_PATH . '/classes/host/class.liquidweb.host.php'); require_once (DUPLICATOR_PLUGIN_PATH . '/classes/host/class.pantheon.host.php'); require_once (DUPLICATOR_PLUGIN_PATH . '/classes/host/class.flywheel.host.php'); class DUP_Custom_Host_Manager { const HOST_GODADDY = 'godaddy'; const HOST_WPENGINE = 'wpengine'; const HOST_WORDPRESSCOM = 'wordpresscom'; const HOST_LIQUIDWEB = 'liquidweb'; const HOST_PANTHEON = 'pantheon'; const HOST_FLYWHEEL = 'flywheel'; /** * * @var DUP_Custom_Host_Manager */ protected static $instance = null; /** * * @var bool */ private $initialized = false; /** * * @var DUP_Host_interface[] */ private $customHostings = array(); /** * * @var string[] */ private $activeHostings = array(); /** * * @return self */ public static function getInstance() { if (is_null(self::$instance)) { self::$instance = new self; } return self::$instance; } private function __construct() { $this->customHostings[DUP_WPEngine_Host::getIdentifier()] = new DUP_WPEngine_Host(); $this->customHostings[DUP_GoDaddy_Host::getIdentifier()] = new DUP_GoDaddy_Host(); $this->customHostings[DUP_WordpressCom_Host::getIdentifier()] = new DUP_WordpressCom_Host(); $this->customHostings[DUP_Liquidweb_Host::getIdentifier()] = new DUP_Liquidweb_Host(); $this->customHostings[DUP_Pantheon_Host::getIdentifier()] = new DUP_Pantheon_Host(); $this->customHostings[DUP_Flywheel_Host::getIdentifier()] = new DUP_Flywheel_Host(); } public function init() { if ($this->initialized) { return true; } foreach ($this->customHostings as $cHost) { if (!($cHost instanceof DUP_Host_interface)) { throw new Exception('Host must implement DUP_Host_interface'); } if ($cHost->isHosting()) { $this->activeHostings[] = $cHost->getIdentifier(); $cHost->init(); } } $this->initialized = true; return true; } public function getActiveHostings() { return $this->activeHostings; } public function isHosting($identifier) { return in_array($identifier, $this->activeHostings); } public function isManaged() { if ($this->isHosting(self::HOST_WORDPRESSCOM)) { return true; } if ($this->isHosting(self::HOST_GODADDY)) { return true; } if ($this->isHosting(self::HOST_WPENGINE)) { return true; } if ($this->isHosting(self::HOST_LIQUIDWEB)) { return true; } if ($this->isHosting(self::HOST_PANTHEON)) { return true; } if ($this->isHosting(self::HOST_FLYWHEEL)) { return true; } if ($this->WPConfigIsNotWriteable()) { return true; } if ($this->notAccessibleCoreDirPresent()) { return true; } return false; } public function WPConfigIsNotWriteable() { $wpConfigPath = duplicator_get_abs_path()."/wp-config.php"; return file_exists($wpConfigPath) && !is_writeable($wpConfigPath); } public function notAccessibleCoreDirPresent() { $absPath = duplicator_get_abs_path(); $coreDirs = array( $absPath.'/wp-admin', $absPath.'/wp-includes', WP_CONTENT_DIR ); foreach ($coreDirs as $coreDir) { if (file_exists($coreDir) && !is_writeable($coreDir)) { return true; } } return false; } public function getHosting($identifier) { if ($this->isHosting($identifier)) { return $this->activeHostings[$identifier]; } else { return false; } } } host/class.pantheon.host.php 0000644 00000001137 15133151516 0012131 0 ustar 00 <?php /** * godaddy custom hosting class * * Standard: PSR-2 * * @package SC\DUPX\HOST * @link http://www.php-fig.org/psr/psr-2/ * */ defined('ABSPATH') || defined('DUPXABSPATH') || exit; class DUP_Pantheon_Host implements DUP_Host_interface { public static function getIdentifier() { return DUP_Custom_Host_Manager::HOST_PANTHEON; } public function isHosting() { return apply_filters('duplicator_pantheon_host_check', file_exists(DupLiteSnapLibIOU::safePathUntrailingslashit(WPMU_PLUGIN_DIR).'/pantheon.php')); } public function init() { } } host/class.godaddy.host.php 0000644 00000001312 15133151516 0011723 0 ustar 00 <?php defined("ABSPATH") or die(""); class DUP_GoDaddy_Host implements DUP_Host_interface { public static function getIdentifier() { return DUP_Custom_Host_Manager::HOST_GODADDY; } public function isHosting() { return apply_filters('duplicator_godaddy_host_check', file_exists(DupLiteSnapLibIOU::safePathUntrailingslashit(WPMU_PLUGIN_DIR).'/gd-system-plugin.php')); } public function init() { add_filter('duplicator_defaults_settings', array(__CLASS__, 'defaultsSettings')); } public static function defaultsSettings($defaults) { $defaults['archive_build_mode'] = DUP_Archive_Build_Mode::DupArchive; return $defaults; } } class.settings.php 0000644 00000024441 15133151516 0010227 0 ustar 00 <?php defined('ABSPATH') || defined('DUPXABSPATH') || exit; // Exit if accessed directly if (!defined('DUPLICATOR_VERSION')) exit; abstract class DUP_Archive_Build_Mode { const Unconfigured = -1; const Auto = 0; // should no longer be used // const Shell_Exec = 1; const ZipArchive = 2; const DupArchive = 3; } class DUP_Settings { const OPT_SETTINGS = 'duplicator_settings'; const INSTALLER_NAME_MODE_WITH_HASH = 'withhash'; const INSTALLER_NAME_MODE_SIMPLE = 'simple'; const STORAGE_POSITION_LECAGY = 'legacy'; const STORAGE_POSITION_WP_CONTENT = 'wpcont'; const SSDIR_NAME_LEGACY = 'wp-snapshots'; const SSDIR_NAME_NEW = 'backups-dup-lite'; protected static $Data; protected static $ssDirPath = null; protected static $ssDirUrl = null; /** * Class used to manage all the settings for the plugin */ public static function init() { self::$Data = get_option(self::OPT_SETTINGS); //when the plugin updated, this will be true if (empty(self::$Data) || empty(self::$Data['version']) || version_compare(DUPLICATOR_VERSION, self::$Data['version'], '>')) { self::SetDefaults(); } } /** * Find the setting value * @param string $key The name of the key to find * @return The value stored in the key returns null if key does not exist */ public static function Get($key = '') { $result = null; if (isset(self::$Data[$key])) { $result = self::$Data[$key]; } else { $defaults = self::GetAllDefaults(); if (isset($defaults[$key])) { $result = $defaults[$key]; } } return $result; } /** * Set the settings value in memory only * @param string $key The name of the key to find * @param string $value The value to set * remarks: The Save() method must be called to write the Settings object to the DB */ public static function Set($key, $value) { if (isset(self::$Data[$key])) { self::$Data[$key] = ($value == null) ? '' : $value; } elseif (!empty($key)) { self::$Data[$key] = ($value == null) ? '' : $value; } } public static function setStoragePosition($newPosition) { $legacyPath = self::getSsdirPathLegacy(); $wpContPath = self::getSsdirPathWpCont(); $oldStoragePost = self::Get('storage_position'); self::resetPositionVars(); switch ($newPosition) { case self::STORAGE_POSITION_LECAGY: self::$Data['storage_position'] = self::STORAGE_POSITION_LECAGY; if (!DUP_Util::initSnapshotDirectory()) { self::resetPositionVars(); self::$Data['storage_position'] = $oldStoragePost; return false; } if (is_dir($wpContPath)) { if (DupLiteSnapLibIOU::moveContentDirToTarget($wpContPath, $legacyPath, true)) { DupLiteSnapLibIOU::rrmdir($wpContPath); } } break; case self::STORAGE_POSITION_WP_CONTENT: self::$Data['storage_position'] = self::STORAGE_POSITION_WP_CONTENT; if (!DUP_Util::initSnapshotDirectory()) { self::resetPositionVars(); self::$Data['storage_position'] = $oldStoragePost; return false; } if (is_dir($legacyPath)) { if (DupLiteSnapLibIOU::moveContentDirToTarget($legacyPath, $wpContPath, true)) { DupLiteSnapLibIOU::rrmdir($legacyPath); } } break; default: throw new Exception('Unknown storage position'); } return true; } protected static function resetPositionVars() { self::$ssDirPath = null; self::$ssDirUrl = null; } /** * Saves all the setting values to the database * @return True if option value has changed, false if not or if update failed. */ public static function Save() { return update_option(self::OPT_SETTINGS, self::$Data); } /** * Deletes all the setting values to the database * @return True if option value has changed, false if not or if update failed. */ public static function Delete() { return delete_option(self::OPT_SETTINGS); } /** * Sets the defaults if they have not been set * @return True if option value has changed, false if not or if update failed. */ public static function SetDefaults() { $defaults = self::GetAllDefaults(); self::$Data = apply_filters('duplicator_defaults_settings', $defaults); return self::Save(); } /** * DeleteWPOption: Cleans up legacy data */ public static function DeleteWPOption($optionName) { if (in_array($optionName, $GLOBALS['DUPLICATOR_OPTS_DELETE'])) { return delete_option($optionName); } return false; } public static function GetAllDefaults() { $default = array(); $default['version'] = DUPLICATOR_VERSION; //Flag used to remove the wp_options value duplicator_settings which are all the settings in this class $default['uninstall_settings'] = isset(self::$Data['uninstall_settings']) ? self::$Data['uninstall_settings'] : true; //Flag used to remove entire wp-snapshot directory $default['uninstall_files'] = isset(self::$Data['uninstall_files']) ? self::$Data['uninstall_files'] : true; //Flag used to remove all tables $default['uninstall_tables'] = isset(self::$Data['uninstall_tables']) ? self::$Data['uninstall_tables'] : true; //Flag used to show debug info $default['package_debug'] = isset(self::$Data['package_debug']) ? self::$Data['package_debug'] : false; //Flag used to enable mysqldump $default['package_mysqldump'] = isset(self::$Data['package_mysqldump']) ? self::$Data['package_mysqldump'] : true; //Optional mysqldump search path $default['package_mysqldump_path'] = isset(self::$Data['package_mysqldump_path']) ? self::$Data['package_mysqldump_path'] : ''; //Optional mysql limit size $default['package_phpdump_qrylimit'] = isset(self::$Data['package_phpdump_qrylimit']) ? self::$Data['package_phpdump_qrylimit'] : "100"; //Optional mysqldump search path $default['package_zip_flush'] = isset(self::$Data['package_zip_flush']) ? self::$Data['package_zip_flush'] : false; //Optional mysqldump search path $default['installer_name_mode'] = isset(self::$Data['installer_name_mode']) ? self::$Data['installer_name_mode'] : self::INSTALLER_NAME_MODE_SIMPLE; // storage position $default['storage_position'] = isset(self::$Data['storage_position']) ? self::$Data['storage_position'] : self::STORAGE_POSITION_WP_CONTENT; //Flag for .htaccess file $default['storage_htaccess_off'] = isset(self::$Data['storage_htaccess_off']) ? self::$Data['storage_htaccess_off'] : false; // Initial archive build mode if (isset(self::$Data['archive_build_mode'])) { $default['archive_build_mode'] = self::$Data['archive_build_mode']; } else { $is_ziparchive_available = apply_filters('duplicator_is_ziparchive_available', class_exists('ZipArchive')); $default['archive_build_mode'] = $is_ziparchive_available ? DUP_Archive_Build_Mode::ZipArchive : DUP_Archive_Build_Mode::DupArchive; } // $default['package_zip_flush'] = apply_filters('duplicator_package_zip_flush_default_setting', '0'); //Skip scan archive $default['skip_archive_scan'] = isset(self::$Data['skip_archive_scan']) ? self::$Data['skip_archive_scan'] : false; $default['unhook_third_party_js'] = isset(self::$Data['unhook_third_party_js']) ? self::$Data['unhook_third_party_js'] : false; $default['unhook_third_party_css'] = isset(self::$Data['unhook_third_party_css']) ? self::$Data['unhook_third_party_css'] : false; $default['active_package_id'] = -1; return $default; } public static function get_create_date_format() { static $ui_create_frmt = null; if (is_null($ui_create_frmt)) { $ui_create_frmt = is_numeric(self::Get('package_ui_created')) ? self::Get('package_ui_created') : 1; } return $ui_create_frmt; } public static function getSsdirPathLegacy() { return DupLiteSnapLibIOU::safePathTrailingslashit(duplicator_get_abs_path()).self::SSDIR_NAME_LEGACY; } public static function getSsdirPathWpCont() { return DupLiteSnapLibIOU::safePathTrailingslashit(WP_CONTENT_DIR).self::SSDIR_NAME_NEW; } public static function getSsdirPath() { if (is_null(self::$ssDirPath)) { if (self::Get('storage_position') === self::STORAGE_POSITION_LECAGY) { self::$ssDirPath = self::getSsdirPathLegacy(); } else { self::$ssDirPath = self::getSsdirPathWpCont(); } } return self::$ssDirPath; } public static function getSsdirUrl() { if (is_null(self::$ssDirUrl)) { if (self::Get('storage_position') === self::STORAGE_POSITION_LECAGY) { self::$ssDirUrl = DupLiteSnapLibIOU::trailingslashit(DUPLICATOR_SITE_URL).self::SSDIR_NAME_LEGACY; } else { self::$ssDirUrl = DupLiteSnapLibIOU::trailingslashit(content_url()).self::SSDIR_NAME_NEW; } } return self::$ssDirUrl; } public static function getSsdirTmpPath() { return self::getSsdirPath().'/tmp'; } public static function getSsdirInstallerPath() { return self::getSsdirPath().'/installer'; } } class.plugin.upgrade.php 0000644 00000004642 15133151516 0011314 0 ustar 00 <?php defined('ABSPATH') || defined('DUPXABSPATH') || exit; /** * Upgrade logic of plugin resides here */ class DUP_LITE_Plugin_Upgrade { const DUP_VERSION_OPT_KEY = 'duplicator_version_plugin'; public static function onActivationAction() { if (($oldDupVersion = get_option(self::DUP_VERSION_OPT_KEY, false)) === false) { self::newInstallation(); } else { self::updateInstallation($oldDupVersion); } //Setup All Directories DUP_Util::initSnapshotDirectory(); } protected static function newInstallation() { self::updateDatabase(); //WordPress Options Hooks update_option(self::DUP_VERSION_OPT_KEY, DUPLICATOR_VERSION); } protected static function updateInstallation($oldVersion) { self::updateDatabase(); //PRE 1.3.35 //Do not update to new wp-content storage till after if (version_compare($oldVersion, '1.3.35', '<')) { DUP_Settings::Set('storage_position', DUP_Settings::STORAGE_POSITION_LECAGY); DUP_Settings::Save(); } //PRE 1.4.7 //Remove the core dup-install file that might exist in local storage directory if (version_compare($oldVersion, '1.4.7', '<')) { $ssdir = DUP_Settings::getSsdirPath(); $dupInstallFile = "{$ssdir}/dup-installer/main.installer.php"; if (file_exists($dupInstallFile) ) { @unlink("{$dupInstallFile}"); } } //WordPress Options Hooks update_option(self::DUP_VERSION_OPT_KEY, DUPLICATOR_VERSION); } protected static function updateDatabase() { global $wpdb; $table_name = $wpdb->prefix."duplicator_packages"; //PRIMARY KEY must have 2 spaces before for dbDelta to work //see: https://codex.wordpress.org/Creating_Tables_with_Plugins $sql = "CREATE TABLE `{$table_name}` ( id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, name VARCHAR(250) NOT NULL, hash VARCHAR(50) NOT NULL, status INT(11) NOT NULL, created DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', owner VARCHAR(60) NOT NULL, package LONGTEXT NOT NULL, PRIMARY KEY (id), KEY hash (hash))"; $abs_path = duplicator_get_abs_path(); require_once($abs_path.'/wp-admin/includes/upgrade.php'); @dbDelta($sql); } } ui/class.ui.messages.php 0000644 00000006501 15133151516 0011224 0 ustar 00 <?php defined('ABSPATH') || defined('DUPXABSPATH') || exit; /** * Used to generate a thick box inline dialog such as an alert or confirm pop-up * * * Standard: PSR-2 * @link http://www.php-fig.org/psr/psr-2 * * @package Duplicator * @subpackage classes/ui * @copyright (c) 2017, Snapcreek LLC */ class DUP_UI_Messages { const UNIQUE_ID_PREFIX = 'dup_ui_msg_'; const NOTICE = 'updated'; const WARNING = 'update-nag'; const ERROR = 'error'; private static $unique_id = 0; private $id; public $type = self::NOTICE; public $content = ''; public $wrap_cont_tag = 'p'; public $hide_on_init = true; public $is_dismissible = false; /** * * @var int delay in milliseconds */ public $auto_hide_delay = 0; public $callback_on_show = null; public $callback_on_hide = null; public function __construct($content = '', $type = self::NOTICE) { self::$unique_id ++; $this->id = self::UNIQUE_ID_PREFIX.self::$unique_id; $this->content = (string) $content; $this->type = $type; } protected function get_notice_classes($classes = array()) { if (is_string($classes)) { $classes = explode(' ', $classes); } else if (is_array($classes)) { } else { $classes = array(); } if ($this->is_dismissible) { $classes[] = 'is-dismissible'; } $result = array_merge(array('notice', $this->type), $classes); return trim(implode(' ', $result)); } public function initMessage() { $classes = array(); if ($this->hide_on_init) { $classes[] = 'no_display'; } $this->wrap_tag = empty($this->wrap_tag) ? 'p' : $this->wrap_tag; echo '<div id="'.$this->id.'" class="'.$this->get_notice_classes($classes).'">'. '<'.$this->wrap_cont_tag.' class="msg-content">'. $this->content. '</'.$this->wrap_cont_tag.'>'. '</div>'; } public function updateMessage($jsVarName, $echo = true) { $result = 'jQuery("#'.$this->id.' > .msg-content").html('.$jsVarName.');'; if ($echo) { echo $result; } else { return $result; } } public function showMessage($echo = true) { $callStr = !empty($this->callback_on_show) ? $this->callback_on_show.';' : ''; $result = 'jQuery("#'.$this->id.'").fadeIn( "slow", function() { $(this).removeClass("no_display");'.$callStr.' });'; if ($this->auto_hide_delay > 0) { $result .= 'setTimeout(function () { '.$this->hideMessage(false).' }, '.$this->auto_hide_delay.');'; } if ($echo) { echo $result; } else { return $result; } } public function hideMessage($echo = true) { $callStr = !empty($this->callback_on_hide) ? $this->callback_on_hide.';' : ''; $result = 'jQuery("#'.$this->id.'").fadeOut( "slow", function() { $(this).addClass("no_display");'.$callStr.' });'; if ($echo) { echo $result; } else { return $result; } } } ui/index.php 0000644 00000000016 15133151516 0006777 0 ustar 00 <?php //silent ui/class.ui.dialog.php 0000644 00000015371 15133151516 0010661 0 ustar 00 <?php defined('ABSPATH') || defined('DUPXABSPATH') || exit; /** * Used to generate a thick-box inline dialog such as an alert or confirm pop-up * * Standard: PSR-2 * @link http://www.php-fig.org/psr/psr-2 * * @package Duplicator * @subpackage classes/ui * @copyright (c) 2017, Snapcreek LLC * */ // Exit if accessed directly if (! defined('DUPLICATOR_VERSION')) exit; class DUP_UI_Dialog { /** * The title that shows up in the dialog */ public $title; /** * The message displayed in the body of the dialog */ public $message; /** * The width of the dialog the default is used if not set * Alert = 475px (default) | Confirm = 500px (default) */ public $width; /** * The height of the dialog the default is used if not set * Alert = 125px (default) | Confirm = 150px (default) */ public $height; /** * When the progress meter is running show this text * Available only on confirm dialogs */ public $progressText; /** * When true a progress meter will run until page is reloaded * Available only on confirm dialogs */ public $progressOn = true; /** * The javascript call back method to call when the 'Yes' button is clicked * Available only on confirm dialogs */ public $jscallback; /** * * @var string */ public $okText; /** * * @var string */ public $cancelText; /** * If true close dialog on confirm * @var bool */ public $closeOnConfirm = false; /** * The id given to the full dialog */ private $id; /** * A unique id that is added to all id elements */ private $uniqid; /** * Init this object when created */ public function __construct() { add_thickbox(); $this->progressText = __('Processing please wait...', 'duplicator'); $this->uniqid = substr(uniqid('',true),0,14) . rand(); $this->id = 'dup-dlg-'.$this->uniqid; $this->okText = __('OK', 'duplicator'); $this->cancelText = __('Cancel', 'duplicator'); } /** * Gets the unique id that is assigned to each instance of a dialog * * @return int The unique ID of this dialog */ public function getID() { return $this->id; } /** * Gets the unique id that is assigned to each instance of a dialogs message text * * @return int The unique ID of the message */ public function getMessageID() { return "{$this->id}_message"; } /** * Initialize the alert base html code used to display when needed * * @return string The html content used for the alert dialog */ public function initAlert() { $onClickClose = ''; if (!is_null($this->jscallback)) { $onClickClose .= $this->jscallback.';'; } $onClickClose .= 'tb_remove();'; if (strlen($this->okText) == 0) { $hideButton = "style='display:none'"; } $html = ' <div id="'.esc_attr($this->id).'" style="display:none"> <div class="dup-dlg-alert-txt"> '.$this->message.' <br/><br/> </div> <div class="dup-dlg-alert-btns"> <input type="button" class="button button-large" value="'.esc_attr($this->okText).'" onclick="'.$onClickClose.'" '. $hideButton . '/> </div> </div>'; echo $html; } /** * Shows the alert base JS code used to display when needed * * @return string The javascript content used for the alert dialog */ public function showAlert() { $this->width = is_numeric($this->width) ? $this->width : 500; $this->height = is_numeric($this->height) ? $this->height : 175; $html = "tb_show('".esc_js($this->title)."', '#TB_inline?width=".esc_js($this->width)."&height=".esc_js($this->height)."&inlineId=".esc_js($this->id)."');\n" . "var styleData = jQuery('#TB_window').attr('style') + 'height: ".esc_js($this->height)."px !important';\n" . "jQuery('#TB_window').attr('style', styleData);"; echo $html; } /** * Shows the confirm base JS code used to display when needed * * @return string The javascript content used for the confirm dialog */ public function initConfirm() { $progress_data = ''; $progress_func2 = ''; $onClickConfirm = ''; if (!is_null($this->jscallback)) { $onClickConfirm .= $this->jscallback.';'; } //Enable the progress spinner if ($this->progressOn) { $progress_func1 = "__DUP_UI_Dialog_".$this->uniqid; $progress_func2 = ";{$progress_func1}(this)"; $progress_data = "<div class='dup-dlg-confirm-progress'><i class='fas fa-circle-notch fa-spin fa-lg fa-fw'></i> ".esc_js($this->progressText)."</div> <script> function {$progress_func1}(obj) { jQuery(obj).parent().parent().find('.dup-dlg-confirm-progress').show(); jQuery(obj).closest('.dup-dlg-confirm-btns').find('input').attr('disabled', 'true'); } </script>"; $onClickConfirm .= $progress_func2.';'; } if ($this->closeOnConfirm) { $onClickConfirm .= 'tb_remove();'; } $html = '<div id="'.esc_attr($this->id).'" style="display:none"> <div class="dup-dlg-confirm-txt"> <span id="'.esc_attr($this->id).'_message">'.esc_html($this->message).'</span> <br/><br/> '.$progress_data.' </div> <div class="dup-dlg-confirm-btns"> <input type="button" class="button button-large" value="'.esc_attr($this->okText).'" onclick="'.$onClickConfirm.'" /> <input type="button" class="button button-large" value="'.esc_attr($this->cancelText).'" onclick="tb_remove()" /> </div> </div>'; echo $html; } /** * Shows the confirm base JS code used to display when needed * * @return string The javascript content used for the confirm dialog */ public function showConfirm() { $this->width = is_numeric($this->width) ? $this->width : 500; $this->height = is_numeric($this->height) ? $this->height : 225; $html = "tb_show('".esc_js($this->title)."', '#TB_inline?width=".esc_js($this->width)."&height=".esc_js($this->height)."&inlineId=".esc_js($this->id)."');\n" . "var styleData = jQuery('#TB_window').attr('style') + 'height: ".esc_js($this->height)."px !important';\n" . "jQuery('#TB_window').attr('style', styleData);"; echo $html; } } ui/class.ui.screen.base.php 0000644 00000010170 15133151516 0011602 0 ustar 00 <?php defined('ABSPATH') || defined('DUPXABSPATH') || exit; /** * The base class for all screen.php files. This class is used to control items that are common * among all screens, namely the Help tab and Screen Options drop down items. When creating a * screen object please extent this class. * * Standard: PSR-2 * @link http://www.php-fig.org/psr/psr-2 * * @package Duplicator * @subpackage classes/ui * @copyright (c) 2017, Snapcreek LLC * */ // Exit if accessed directly if (!defined('DUPLICATOR_VERSION')) exit; class DUP_UI_Screen { /** * Used as a placeholder for the current screen object */ public $screen; /** * Init this object when created */ public function __construct() { } public static function getCustomCss() { $screen = get_current_screen(); if (!in_array($screen->id, array( 'toplevel_page_duplicator', 'duplicator_page_duplicator-tools', 'duplicator_page_duplicator-settings', 'duplicator_page_duplicator-gopro'))) { return; } $colorScheme = self::getCurrentColorScheme(); if ($colorScheme !== false) { ?> <style> .link-style { color: <?php echo $colorScheme->colors[2]; ?>; } .link-style:hover { color: <?php echo $colorScheme->colors[3]; ?>; } </style> <?php } } public static function getCurrentColorScheme() { global $_wp_admin_css_colors; if(!isset($_wp_admin_css_colors) || !is_array($_wp_admin_css_colors)){ return false; } $colorScheme = get_user_option('admin_color'); if (isset($_wp_admin_css_colors[$colorScheme])) { return $_wp_admin_css_colors[$colorScheme]; } else { return $_wp_admin_css_colors[DupLiteSnapLibUtil::arrayKeyFirst($_wp_admin_css_colors)]; } } /** * Get the help support tab view content shown in the help system * * @param string $guide The target URL to navigate to on the online user guide * @param string $faq The target URL to navigate to on the online user tech FAQ * * @return null */ public function getSupportTab($guide, $faq) { $content = __("<b>Need Help?</b> Please check out these resources first:" ."<ul>" ."<li><a href='https://snapcreek.com/duplicator/docs/guide{$guide}' target='_sc-faq'>Full Online User Guide</a></li>" ."<li><a href='https://snapcreek.com/duplicator/docs/faqs-tech{$faq}' target='_sc-faq'>Frequently Asked Questions</a></li>" ."</ul>", 'duplicator'); $this->screen->add_help_tab(array( 'id' => 'dup_help_tab_callback', 'title' => esc_html__('Support', 'duplicator'), 'content' => "<p>{$content}</p>" ) ); } /** * Get the help support side bar found in the right most part of the help system * * @return null */ public function getHelpSidbar() { $txt_title = __("Resources", 'duplicator'); $txt_home = __("Knowledge Base", 'duplicator'); $txt_guide = __("Full User Guide", 'duplicator'); $txt_faq = __("Technical FAQs", 'duplicator'); $txt_sets = __("Package Settings", 'duplicator'); $this->screen->set_help_sidebar( "<div class='dup-screen-hlp-info'><b>".esc_html($txt_title).":</b> <br/>" ."<i class='fa fa-home'></i> <a href='https://snapcreek.com/duplicator/docs/' target='_sc-home'>".esc_html($txt_home)."</a> <br/>" ."<i class='fa fa-book'></i> <a href='https://snapcreek.com/duplicator/docs/guide/' target='_sc-guide'>".esc_html($txt_guide)."</a> <br/>" ."<i class='far fa-file-code'></i> <a href='https://snapcreek.com/duplicator/docs/faqs-tech/' target='_sc-faq'>".esc_html($txt_faq)."</a> <br/>" ."<i class='fa fa-cog'></i> <a href='admin.php?page=duplicator-settings&tab=package'>".esc_html($txt_sets)."</a></div>" ); } } ui/class.ui.notice.php 0000644 00000036166 15133151516 0010710 0 ustar 00 <?php defined('ABSPATH') || defined('DUPXABSPATH') || exit; /** * Used to display notices in the WordPress Admin area * This class takes advantage of the admin_notice action. * * Standard: PSR-2 * @link http://www.php-fig.org/psr/psr-2 * * @package Duplicator * @subpackage classes/ui * @copyright (c) 2017, Snapcreek LLC * */ class DUP_UI_Notice { const OPTION_KEY_ACTIVATE_PLUGINS_AFTER_INSTALL = 'duplicator_reactivate_plugins_after_installation'; //TEMPLATE VALUE: This is a just a simple example for setting up quick notices const OPTION_KEY_NEW_NOTICE_TEMPLATE = 'duplicator_new_template_notice'; const OPTION_KEY_IS_PRO_ENABLE_NOTICE_DISMISSED = 'duplicator_is_pro_enable_notice_dismissed'; const OPTION_KEY_IS_MU_NOTICE_DISMISSED = 'duplicator_is_mu_notice_dismissed'; const GEN_INFO_NOTICE = 0; const GEN_SUCCESS_NOTICE = 1; const GEN_WARNING_NOTICE = 2; const GEN_ERROR_NOTICE = 3; /** * init notice actions */ public static function init() { $methods = array( 'showReservedFilesNotice', 'installAutoDeactivatePlugins', 'showFeedBackNotice', 'showNoExportCapabilityNotice', //FUTURE NOTICE TEMPLATE //'newNotice_TEMPLATE', ); foreach ($methods as $method) { add_action('admin_notices', array(__CLASS__, $method)); } } /** * NOTICE SAMPLE: This method serves as a quick example for how to quickly setup a new notice * Please do not edit this method, but simply use to copy a new setup. */ public static function newNotice_TEMPLATE() { if (get_option(self::OPTION_KEY_NEW_NOTICE_TEMPLATE) != true) { return; } $screen = get_current_screen(); if (!in_array($screen->parent_base, array('plugins', 'duplicator'))) { return; } ?> <div class="notice notice-success duplicator-admin-notice is-dismissible" data-to-dismiss="<?php echo esc_attr(self::OPTION_KEY_NEW_NOTICE_TEMPLATE); ?>" > <p> <?php esc_html_e('NOTICE: This is a sample message notice demo.', 'duplicator'); ?><br> <?php echo sprintf(__('Example for passing dynamic data to notice message <i>%s</i> to <i>%s</i>', 'duplicator'), esc_html("test 1"), esc_html(time())); ?> </p> <p> <?php echo sprintf(__('More info here: Goto <a href="%s">General Settings</a>', 'duplicator'), 'admin.php?page=duplicator-settings'); ?> </p> </div> <?php } /** * Shows a display message in the wp-admin if any reserved files are found * * @return string Html formatted text notice warnings */ public static function showReservedFilesNotice() { //Show only on Duplicator pages and Dashboard when plugin is active $dup_active = is_plugin_active('duplicator/duplicator.php'); $dup_perm = current_user_can('manage_options'); if (!$dup_active || !$dup_perm) return; $screen = get_current_screen(); if (!isset($screen)) return; $is_installer_cleanup_req = ($screen->id == 'duplicator_page_duplicator-tools' && isset($_GET['action']) && $_GET['action'] == 'installer'); if (DUP_Server::hasInstallerFiles() && !$is_installer_cleanup_req) { DUP_Migration::renameInstallersPhpFiles(); $on_active_tab = isset($_GET['section']) ? $_GET['section'] : ''; echo '<div class="dup-updated notice notice-success dup-global-error-reserved-files" id="message"><p>'; //Safe Mode Notice $safe_html = ''; if (get_option("duplicator_exe_safe_mode", 0) > 0) { $safe_msg1 = __('Safe Mode:', 'duplicator'); $safe_msg2 = __('During the install safe mode was enabled deactivating all plugins.<br/> Please be sure to ', 'duplicator'); $safe_msg3 = __('re-activate the plugins', 'duplicator'); $safe_html = "<div class='notice-safemode'><b>{$safe_msg1}</b><br/>{$safe_msg2} <a href='plugins.php'>{$safe_msg3}</a>!</div><br/>"; } //On Tools > Cleanup Page if ($screen->id == 'duplicator_page_duplicator-tools' && ($on_active_tab == "info" || $on_active_tab == '')) { $title = __('This site has been successfully migrated!', 'duplicator'); $msg1 = __('Final step(s):', 'duplicator'); $msg2 = __('This message will be removed after all installer files are removed. Installer files must be removed to maintain a secure site. ' .'Click the link above or button below to remove all installer files and complete the migration.', 'duplicator'); echo "<b class='pass-msg'><i class='fa fa-check-circle'></i> ".esc_html($title)."</b> <br/> {$safe_html} <b>".esc_html($msg1)."</b> <br/>"; printf("1. <a href='javascript:void(0)' onclick='jQuery(\"#dup-remove-installer-files-btn\").click()'>%s</a><br/>", esc_html__('Remove Installation Files Now!', 'duplicator')); printf("2. <a href='https://wordpress.org/support/plugin/duplicator/reviews/?filter=5' target='wporg'>%s</a> <br/> ", esc_html__('Optionally, Review Duplicator at WordPress.org...', 'duplicator')); echo "<div class='pass-msg'>".esc_html($msg2)."</div>"; //All other Pages } else { $title = __('Migration Almost Complete!', 'duplicator'); $msg = __('Reserved Duplicator installation files have been detected in the root directory. Please delete these installation files to ' .'avoid security issues. <br/> Go to:Duplicator > Tools > Information >Stored Data and click the "Remove Installation Files" button', 'duplicator'); $nonce = wp_create_nonce('duplicator_cleanup_page'); $url = self_admin_url('admin.php?page=duplicator-tools&tab=diagnostics§ion=info&_wpnonce='.$nonce); echo "<b>{$title}</b><br/> {$safe_html} {$msg}"; @printf("<br/><a href='{$url}'>%s</a>", __('Take me there now!', 'duplicator')); } echo "</p></div>"; } } /** * Shows a message for redirecting a page * * @return string The location to redirect to */ public static function redirect($location) { echo '<div class="dup-redirect"><i class="fas fa-circle-notch fa-spin fa-fw"></i>'; esc_html__('Redirecting Please Wait...', 'duplicator'); echo '</div>'; echo "<script>window.location = '{$location}';</script>"; die(esc_html__('Invalid token permissions to perform this request.', 'duplicator')); } /** * Shows install deactivated function */ public static function installAutoDeactivatePlugins() { $reactivatePluginsAfterInstallation = get_option(self::OPTION_KEY_ACTIVATE_PLUGINS_AFTER_INSTALL, false); if (is_array($reactivatePluginsAfterInstallation)) { $installedPlugins = array_keys(get_plugins()); $shouldBeActivated = array(); foreach ($reactivatePluginsAfterInstallation as $pluginSlug => $pluginTitle) { if (in_array($pluginSlug, $installedPlugins) && !is_plugin_active($pluginSlug)) { $shouldBeActivated[$pluginSlug] = $pluginTitle; } } if (empty($shouldBeActivated)) { delete_option(self::OPTION_KEY_ACTIVATE_PLUGINS_AFTER_INSTALL); } else { $activatePluginsAnchors = array(); foreach ($shouldBeActivated as $slug => $title) { $activateURL = wp_nonce_url(admin_url('plugins.php?action=activate&plugin='.$slug), 'activate-plugin_'.$slug); $anchorTitle = sprintf(esc_html__('Activate %s', 'duplicator'), $title); $activatePluginsAnchors[] = '<a href="'.$activateURL.'" title="'.esc_attr($anchorTitle).'">'. $title.'</a>'; } ?> <div class="update-nag duplicator-plugin-activation-admin-notice notice notice-warning duplicator-admin-notice is-dismissible" data-to-dismiss="<?php echo esc_attr(self::OPTION_KEY_ACTIVATE_PLUGINS_AFTER_INSTALL); ?>" > <p> <?php echo "<b>".esc_html__("Warning!", "duplicator")."</b> ".esc_html__("Migration Almost Complete!", "duplicator")." <br/>"; echo esc_html__("Plugin(s) listed here have been deactivated during installation to help prevent issues. Please activate them to finish this migration: ", "duplicator")."<br/>"; echo implode(' ,', $activatePluginsAnchors); ?> </p> </div> <?php } } } /** * Shows feedback notices after certain no. of packages successfully created */ public static function showFeedBackNotice() { $notice_id = 'rate_us_feedback'; if (!current_user_can('manage_options')) { return; } $notices = get_user_meta(get_current_user_id(), DUPLICATOR_ADMIN_NOTICES_USER_META_KEY, true); if (empty($notices)) { $notices = array(); } $duplicator_pages = array( 'toplevel_page_duplicator', 'duplicator_page_duplicator-tools', 'duplicator_page_duplicator-settings', 'duplicator_page_duplicator-gopro', ); if (!in_array(get_current_screen()->id, $duplicator_pages) || (isset($notices[$notice_id]) && 'true' === $notices[$notice_id])) { return; } // not using DUP_Util::getTablePrefix() in place of $tablePrefix because DUP_UI_Notice included initially (Duplicator\Lite\Requirement is depended on the DUP_UI_Notice) $tablePrefix = (is_multisite() && is_plugin_active_for_network('duplicator/duplicator.php')) ? $GLOBALS['wpdb']->base_prefix : $GLOBALS['wpdb']->prefix; $packagesCount = $GLOBALS['wpdb']->get_var('SELECT count(id) FROM '.$tablePrefix.'duplicator_packages WHERE status=100'); if ($packagesCount < DUPLICATOR_FEEDBACK_NOTICE_SHOW_AFTER_NO_PACKAGE) { return; } $notices[$notice_id] = 'false'; update_user_meta(get_current_user_id(), DUPLICATOR_ADMIN_NOTICES_USER_META_KEY, $notices); $dismiss_url = wp_nonce_url( add_query_arg(array( 'action' => 'duplicator_set_admin_notice_viewed', 'notice_id' => esc_attr($notice_id), ), admin_url('admin-post.php')), 'duplicator_set_admin_notice_viewed', 'nonce' ); ?> <div class="notice updated duplicator-message duplicator-message-dismissed" data-notice_id="<?php echo esc_attr($notice_id); ?>"> <div class="duplicator-message-inner"> <div class="duplicator-message-icon"> <img src="<?php echo esc_url(DUPLICATOR_PLUGIN_URL."assets/img/logo.png"); ?>" style="text-align:top; margin:0; height:60px; width:60px;" alt="Duplicator"> </div> <div class="duplicator-message-content"> <p><strong><?php echo __('Congrats!', 'duplicator'); ?></strong> <?php printf(esc_html__('You created over %d packages with Duplicator. Great job! If you can spare a minute, please help us by leaving a five star review on WordPress.org.', 'duplicator'), DUPLICATOR_FEEDBACK_NOTICE_SHOW_AFTER_NO_PACKAGE); ?></p> <p class="duplicator-message-actions"> <a href="https://wordpress.org/support/plugin/duplicator/reviews/?filter=5/#new-post" target="_blank" class="button button-primary duplicator-notice-rate-now"><?php esc_html_e("Sure! I'd love to help", 'duplicator'); ?></a> <a href="<?php echo esc_url_raw($dismiss_url); ?>" class="button duplicator-notice-dismiss"><?php esc_html_e('Hide Notification', 'duplicator'); ?></a> </p> </div> </div> </div> <?php } /** * Shows a display message in the wp-admin if the logged in user role has not export capability * * @return void */ public static function showNoExportCapabilityNotice() { if (is_admin() && in_array('administrator', $GLOBALS['current_user']->roles) && !current_user_can('export')) { $errorMessage = __('<strong>Duplicator</strong><hr> Your logged-in user role does not have export capability so you don\'t have access to Duplicator functionality.', 'duplicator'). "<br>". sprintf(__('<strong>RECOMMENDATION:</strong> Add export capability to your role. See FAQ: <a target="_blank" href="%s">%s</a>', 'duplicator'), 'https://snapcreek.com/duplicator/docs/faqs-tech/#faq-licensing-040-q', __('Why is the Duplicator/Packages menu missing from my admin menu?', 'duplicator')); DUP_UI_Notice::displayGeneralAdminNotice($errorMessage, self::GEN_ERROR_NOTICE, true); } } /** * display genral admin notice by printing it * * @param string $htmlMsg html code to be printed * @param integer $noticeType constant value of SELF::GEN_ * @param boolean $isDismissible whether the notice is dismissable or not. Default is true * @param array|string $extraClasses add more classes to the notice div * @return void */ public static function displayGeneralAdminNotice($htmlMsg, $noticeType, $isDismissible = true, $extraClasses = array()) { if (empty($extraClasses)) { $classes = array(); } elseif (is_array($extraClasses)) { $classes = $extraClasses; } else { $classes = array($extraClasses); } $classes[] = 'notice'; switch ($noticeType) { case self::GEN_INFO_NOTICE: $classes[] = 'notice-info'; break; case self::GEN_SUCCESS_NOTICE: $classes[] = 'notice-success'; break; case self::GEN_WARNING_NOTICE: $classes[] = 'notice-warning'; break; case self::GEN_ERROR_NOTICE: $classes[] = 'notice-error'; break; default: throw new Exception('Invalid Admin notice type!'); } if ($isDismissible) { $classes[] = 'is-dismissible'; } $classesStr = implode(' ', $classes); ?> <div class="<?php echo esc_attr($classesStr); ?>"> <p> <?php if (self::GEN_ERROR_NOTICE == $noticeType) { ?> <i class='fa fa-exclamation-triangle'></i> <?php } ?> <?php echo $htmlMsg; ?> </p> </div> <?php } } ui/class.ui.viewstate.php 0000644 00000004457 15133151516 0011440 0 ustar 00 <?php defined('ABSPATH') || defined('DUPXABSPATH') || exit; /** * Gets the view state of UI elements to remember its viewable state * * Standard: PSR-2 * @link http://www.php-fig.org/psr/psr-2 * * @package Duplicator * @subpackage classes/ui * @copyright (c) 2017, Snapcreek LLC * */ // Exit if accessed directly if (! defined('DUPLICATOR_VERSION')) exit; class DUP_UI_ViewState { /** * The key used in the wp_options table * * @var string */ private static $optionsViewStateKey = 'duplicator_ui_view_state'; /** * Save the view state of UI elements * * @param string $key A unique key to define the UI element * @param string $value A generic value to use for the view state * * @return bool Returns true if the value was successfully saved */ public static function save($key, $value) { $view_state = array(); $view_state = get_option(self::$optionsViewStateKey); $view_state[$key] = $value; $success = update_option(self::$optionsViewStateKey, $view_state); return $success; } /** * Gets all the values from the settings array * * @return array Returns and array of all the values stored in the settings array */ public static function getArray() { return get_option(self::$optionsViewStateKey); } /** * Sets all the values from the settings array * @param array $view_state states * * @return boolean Returns whether updated or not */ public static function setArray($view_state) { return update_option(self::$optionsViewStateKey, $view_state); } /** * Return the value of the of view state item * * @param type $searchKey The key to search on * @return string Returns the value of the key searched or null if key is not found */ public static function getValue($searchKey) { $view_state = get_option(self::$optionsViewStateKey); if (is_array($view_state)) { foreach ($view_state as $key => $value) { if ($key == $searchKey) { return $value; } } } return null; } } class.db.php 0000644 00000020052 15133151516 0006746 0 ustar 00 <?php defined('ABSPATH') || defined('DUPXABSPATH') || exit; /** * Lightweight abstraction layer for common simple database routines * * Standard: PSR-2 * @link http://www.php-fig.org/psr/psr-2 * * @package Duplicator * @subpackage classes/utilities * @copyright (c) 2017, Snapcreek LLC * */ // Exit if accessed directly if (!defined('DUPLICATOR_VERSION')) exit; class DUP_DB extends wpdb { const MAX_TABLE_COUNT_IN_PACKET = 100; public static $remove_placeholder_escape_exists = null; public static function init() { global $wpdb; self::$remove_placeholder_escape_exists = method_exists($wpdb, 'remove_placeholder_escape'); } /** * Get the requested MySQL system variable * * @param string $name The database variable name to lookup * * @return string the server variable to query for */ public static function getVariable($name) { global $wpdb; if (strlen($name)) { $row = $wpdb->get_row("SHOW VARIABLES LIKE '{$name}'", ARRAY_N); return isset($row[1]) ? $row[1] : null; } else { return null; } } /** * Gets the MySQL database version number * * @param bool $full True: Gets the full version * False: Gets only the numeric portion i.e. 5.5.6 or 10.1.2 (for MariaDB) * * @return false|string 0 on failure, version number on success */ public static function getVersion($full = false) { global $wpdb; if ($full) { $version = self::getVariable('version'); } else { $version = preg_replace('/[^0-9.].*/', '', self::getVariable('version')); } //Fall-back for servers that have restricted SQL for SHOW statement if (empty($version)) { $version = $wpdb->db_version(); } return empty($version) ? 0 : $version; } /** * Try to return the mysqldump path on Windows servers * * @return boolean|string */ public static function getWindowsMySqlDumpRealPath() { if (function_exists('php_ini_loaded_file')) { $get_php_ini_path = php_ini_loaded_file(); if (file_exists($get_php_ini_path)) { $search = array( dirname(dirname($get_php_ini_path)).'/mysql/bin/mysqldump.exe', dirname(dirname(dirname($get_php_ini_path))).'/mysql/bin/mysqldump.exe', dirname(dirname($get_php_ini_path)).'/mysql/bin/mysqldump', dirname(dirname(dirname($get_php_ini_path))).'/mysql/bin/mysqldump', ); foreach ($search as $mysqldump) { if (file_exists($mysqldump)) { return str_replace("\\", "/", $mysqldump); } } } } unset($search); unset($get_php_ini_path); return false; } /** * Returns the correct database build mode PHP, MYSQLDUMP, PHPCHUNKING * * @return string Returns a string with one of theses three values PHP, MYSQLDUMP, PHPCHUNKING */ public static function getBuildMode() { $package_mysqldump = DUP_Settings::Get('package_mysqldump'); $mysqlDumpPath = DUP_DB::getMySqlDumpPath(); return ($mysqlDumpPath && $package_mysqldump) ? 'MYSQLDUMP' : 'PHP'; } /** * Returns the mysqldump path if the server is enabled to execute it otherwise false * * @return boolean|string */ public static function getMySqlDumpPath() { //Is shell_exec possible if (!DUP_Util::hasShellExec()) { return false; } $custom_mysqldump_path = DUP_Settings::Get('package_mysqldump_path'); $custom_mysqldump_path = (strlen($custom_mysqldump_path)) ? $custom_mysqldump_path : ''; //Common Windows Paths if (DUP_Util::isWindows()) { $paths = array( $custom_mysqldump_path, 'mysqldump.exe', self::getWindowsMySqlDumpRealPath(), 'C:/xampp/mysql/bin/mysqldump.exe', 'C:/Program Files/xampp/mysql/bin/mysqldump', 'C:/Program Files/MySQL/MySQL Server 6.0/bin/mysqldump', 'C:/Program Files/MySQL/MySQL Server 5.5/bin/mysqldump', 'C:/Program Files/MySQL/MySQL Server 5.4/bin/mysqldump' ); //Common Linux Paths } else { $paths = array( $custom_mysqldump_path, 'mysqldump', '/usr/local/bin/mysqldump', '/usr/local/mysql/bin/mysqldump', '/usr/mysql/bin/mysqldump', '/usr/bin/mysqldump', '/opt/local/lib/mysql6/bin/mysqldump', '/opt/local/lib/mysql5/bin/mysqldump', '/usr/bin/mysqldump', ); } $exec_available = function_exists('exec'); foreach ($paths as $path) { if (@file_exists($path)) { if (DUP_Util::isExecutable($path)) { return $path; } } elseif ($exec_available) { $out = array(); $rc = -1; $cmd = $path . ' --help'; @exec($cmd, $out, $rc); if ($rc === 0) { return $path; } } } return false; } /** * Returns all collation types that are assigned to the tables and columns table in * the current database. Each element in the array is unique * * @param array &$tablesToInclude A list of tables to include in the search. * Parameter does not change in the function, is passed by reference only to avoid copying. * * @return array Returns an array with all the collation types being used */ public static function getTableCollationList(&$tablesToInclude) { global $wpdb; static $collations = null; if (is_null($collations)) { $collations = array(); //use half the number of tables since we are using them twice foreach (array_chunk($tablesToInclude, self::MAX_TABLE_COUNT_IN_PACKET) as $tablesChunk) { $sqlTables = implode(",", array_map(array(__CLASS__, 'escValueToQueryString'), $tablesChunk)); //UNION is by default DISTINCT $query = "SELECT `COLLATION_NAME` FROM `information_schema`.`columns` WHERE `COLLATION_NAME` IS NOT NULL AND `table_schema` = '{$wpdb->dbname}' " . "AND `table_name` in (" . $sqlTables . ")" . "UNION SELECT `TABLE_COLLATION` FROM `information_schema`.`tables` WHERE `TABLE_COLLATION` IS NOT NULL AND `table_schema` = '{$wpdb->dbname}' " . "AND `table_name` in (" . $sqlTables . ")"; if (!$wpdb->query($query)) { DUP_Log::Info("GET TABLE COLLATION ERROR: " . $wpdb->last_error); continue; } $collations = array_unique(array_merge($collations, $wpdb->get_col())); } sort($collations); } return $collations; } /** * Returns an escaped SQL string * * @param string $sql The SQL to escape * @param bool $removePlaceholderEscape Patch for how the default WP function works. * * @return boolean|string * @also see: https://make.wordpress.org/core/2017/10/31/changed-behaviour-of-esc_sql-in-wordpress-4-8-3/ */ public static function escSQL($sql, $removePlaceholderEscape = false) { global $wpdb; $removePlaceholderEscape = $removePlaceholderEscape && self::$remove_placeholder_escape_exists; if ($removePlaceholderEscape) { return $wpdb->remove_placeholder_escape(@esc_sql($sql)); } else { return @esc_sql($sql); } } /** * this function escape sql string without add and remove remove_placeholder_escape * doesn't work on array * * @global type $wpdb * @param mixed $sql * @return string */ public static function escValueToQueryString($value) { global $wpdb; if (is_null($value)) { return 'NULL'; } if ($wpdb->use_mysqli) { return '"'.mysqli_real_escape_string($wpdb->dbh, $value).'"'; } else { return '"'.mysql_real_escape_string($value, $wpdb->dbh).'"'; } } } class.password.php 0000644 00000014360 15133151516 0010230 0 ustar 00 <?php defined('ABSPATH') || defined('DUPXABSPATH') || exit; # # Portable PHP password hashing framework. # # Version 0.5 / genuine. # # Written by Solar Designer <solar at openwall.com> in 2004-2006 and placed in # the public domain. Revised in subsequent years, still public domain. # # There's absolutely no warranty. # # The homepage URL for this framework is: # # http://www.openwall.com/phpass/ # # Please be sure to update the Version line if you edit this file in any way. # It is suggested that you leave the main version number intact, but indicate # your project name (after the slash) and add your own revision information. # # Please do not change the "private" password hashing method implemented in # here, thereby making your hashes incompatible. However, if you must, please # change the hash type identifier (the "$P$") to something different. # # Obviously, since this code is in the public domain, the above are not # requirements (there can be none), but merely suggestions. # // Exit if accessed directly if (! defined('DUPLICATOR_VERSION')) exit; class DUP_PasswordHash { var $itoa64; var $iteration_count_log2; var $portable_hashes; var $random_state; function __construct($iteration_count_log2, $portable_hashes) { $this->itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31) $iteration_count_log2 = 8; $this->iteration_count_log2 = $iteration_count_log2; $this->portable_hashes = $portable_hashes; $this->random_state = microtime(); if (function_exists('getmypid')) $this->random_state .= getmypid(); } function PasswordHash($iteration_count_log2, $portable_hashes) { self::__construct($iteration_count_log2, $portable_hashes); } function get_random_bytes($count) { $output = ''; if (@is_readable('/dev/urandom') && ($fh = @fopen('/dev/urandom', 'rb'))) { $output = fread($fh, $count); fclose($fh); } if (strlen($output) < $count) { $output = ''; for ($i = 0; $i < $count; $i += 16) { $this->random_state = md5(microtime() . $this->random_state); $output .= md5($this->random_state, TRUE); } $output = substr($output, 0, $count); } return $output; } function encode64($input, $count) { $output = ''; $i = 0; do { $value = ord($input[$i++]); $output .= $this->itoa64[$value & 0x3f]; if ($i < $count) $value |= ord($input[$i]) << 8; $output .= $this->itoa64[($value >> 6) & 0x3f]; if ($i++ >= $count) break; if ($i < $count) $value |= ord($input[$i]) << 16; $output .= $this->itoa64[($value >> 12) & 0x3f]; if ($i++ >= $count) break; $output .= $this->itoa64[($value >> 18) & 0x3f]; } while ($i < $count); return $output; } function gensalt_private($input) { $output = '$P$'; $output .= $this->itoa64[min($this->iteration_count_log2 + ((PHP_VERSION >= '5') ? 5 : 3), 30)]; $output .= $this->encode64($input, 6); return $output; } function crypt_private($password, $setting) { $output = '*0'; if (substr($setting, 0, 2) === $output) $output = '*1'; $id = substr($setting, 0, 3); # We use "$P$", phpBB3 uses "$H$" for the same thing if ($id !== '$P$' && $id !== '$H$') return $output; $count_log2 = strpos($this->itoa64, $setting[3]); if ($count_log2 < 7 || $count_log2 > 30) return $output; $count = 1 << $count_log2; $salt = substr($setting, 4, 8); if (strlen($salt) !== 8) return $output; # We were kind of forced to use MD5 here since it's the only # cryptographic primitive that was available in all versions # of PHP in use. To implement our own low-level crypto in PHP # would have resulted in much worse performance and # consequently in lower iteration counts and hashes that are # quicker to crack (by non-PHP code). $hash = md5($salt . $password, TRUE); do { $hash = md5($hash . $password, TRUE); } while (--$count); $output = substr($setting, 0, 12); $output .= $this->encode64($hash, 16); return $output; } function gensalt_blowfish($input) { # This one needs to use a different order of characters and a # different encoding scheme from the one in encode64() above. # We care because the last character in our encoded string will # only represent 2 bits. While two known implementations of # bcrypt will happily accept and correct a salt string which # has the 4 unused bits set to non-zero, we do not want to take # chances and we also do not want to waste an additional byte # of entropy. $itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; $output = '$2a$'; $output .= chr(ord('0') + (int)($this->iteration_count_log2 / 10)); $output .= chr(ord('0') + $this->iteration_count_log2 % 10); $output .= '$'; $i = 0; do { $c1 = ord($input[$i++]); $output .= $itoa64[$c1 >> 2]; $c1 = ($c1 & 0x03) << 4; if ($i >= 16) { $output .= $itoa64[$c1]; break; } $c2 = ord($input[$i++]); $c1 |= $c2 >> 4; $output .= $itoa64[$c1]; $c1 = ($c2 & 0x0f) << 2; $c2 = ord($input[$i++]); $c1 |= $c2 >> 6; $output .= $itoa64[$c1]; $output .= $itoa64[$c2 & 0x3f]; } while (1); return $output; } function HashPassword($password) { $random = ''; if (CRYPT_BLOWFISH === 1 && !$this->portable_hashes) { $random = $this->get_random_bytes(16); $hash = crypt($password, $this->gensalt_blowfish($random)); if (strlen($hash) === 60) return $hash; } if (strlen($random) < 6) $random = $this->get_random_bytes(6); $hash = $this->crypt_private($password, $this->gensalt_private($random)); if (strlen($hash) === 34) return $hash; # Returning '*' on error is safe here, but would _not_ be safe # in a crypt(3)-like function used _both_ for generating new # hashes and for validating passwords against existing hashes. return '*'; } function CheckPassword($password, $stored_hash) { $hash = $this->crypt_private($password, $stored_hash); if ($hash[0] === '*') $hash = crypt($password, $stored_hash); return $hash === $stored_hash; } } class.logging.php 0000644 00000035515 15133151516 0010021 0 ustar 00 <?php defined('ABSPATH') || defined('DUPXABSPATH') || exit; // Exit if accessed directly if (!defined('DUPLICATOR_VERSION')) exit; /** * Helper Class for logging * @package Duplicator\classes */ abstract class Dup_ErrorBehavior { const LogOnly = 0; const ThrowException = 1; const Quit = 2; } class DUP_Log { /** * The file handle used to write to the package log file */ private static $logFileHandle = null; /** * Get the setting which indicates if tracing is enabled */ private static $traceEnabled = false; public static $profileLogs = null; /** * Init this static object */ public static function Init() { self::$traceEnabled = (DUP_Settings::Get('trace_log_enabled') == 1); } /** * Open a log file connection for writing to the package log file * * @param string $nameHas The Name of the log file to create * * @return nul */ public static function Open($nameHash) { if (!isset($nameHash)) { throw new Exception("A name value is required to open a file log."); } self::Close(); if ((self::$logFileHandle = @fopen(DUP_Settings::getSsdirPath()."/{$nameHash}.log", "a+")) === false) { self::$logFileHandle = null; return false; } else { /** * By initializing the error_handler on opening the log, I am sure that when a package is processed, the handler is active. */ DUP_Handler::init_error_handler(); return true; } } /** * Close the package log file connection if is opened * * @return bool Returns TRUE on success or FALSE on failure. */ public static function Close() { $result = true; if (!is_null(self::$logFileHandle)) { $result = @fclose(self::$logFileHandle); self::$logFileHandle = null; } else { $result = true; } return $result; } /** * General information send to the package log if opened * @param string $msg The message to log * * REPLACE TO DEBUG: Memory consumption as script runs * $results = DUP_Util::byteSize(memory_get_peak_usage(true)) . "\t" . $msg; * @fwrite(self::$logFileHandle, "{$results} \n"); * * @param string $msg The message to log * * @return null */ public static function Info($msg) { if (self::$traceEnabled) { self::Trace($msg); } if (!is_null(self::$logFileHandle)) { @fwrite(self::$logFileHandle, $msg."\n"); } } public static function print_r_info($val, $name = '') { $msg = empty($name) ? '' : 'VALUE '.$name.': '; $msg .= print_r($val, true); self::info($msg); } /** * Does the trace file exists * * @return bool Returns true if an active trace file exists */ public static function TraceFileExists() { $file_path = self::getTraceFilepath(); return file_exists($file_path); } /** * Gets the current file size of the active trace file * * @return string Returns a human readable file size of the active trace file */ public static function getTraceStatus() { $file_path = DUP_Log::getTraceFilepath(); $backup_path = DUP_Log::getBackupTraceFilepath(); if (file_exists($file_path)) { $filesize = is_file($file_path) ? @filesize($file_path) : 0; //Its possible mulitple trace log files exist due to size if (is_file($backup_path)) { $filesize += @filesize($backup_path); } $message = sprintf('%1$s', DUP_Util::byteSize($filesize)); } else { $message = esc_html__('No Log', 'duplicator'); } return $message; } // RSR TODO: Swap trace logic out for real trace later public static function Trace($message, $calling_function_override = null) { if (self::$traceEnabled) { $unique_id = sprintf("%08x", abs(crc32($_SERVER['REMOTE_ADDR'].$_SERVER['REQUEST_TIME'].$_SERVER['REMOTE_PORT']))); if ($calling_function_override == null) { $calling_function = DupLiteSnapLibUtil::getCallingFunctionName(); } else { $calling_function = $calling_function_override; } if (is_object($message)) { $ov = get_object_vars($message); $message = print_r($ov, true); } else if (is_array($message)) { $message = print_r($message, true); } $logging_message = "{$unique_id}|{$calling_function} | {$message}"; $ticks = time() + ((int) get_option('gmt_offset') * 3600); $formatted_time = date('d-m-H:i:s', $ticks); $formatted_logging_message = "{$formatted_time}|DUP|{$logging_message} \r\n"; // Always write to error log - if they don't want the info they can turn off WordPress error logging or tracing self::ErrLog($logging_message); // Everything goes to the plugin log, whether it's part of package generation or not. self::WriteToTrace($formatted_logging_message); } } public static function print_r_trace($val, $name = '', $calling_function_override = null) { $msg = empty($name) ? '' : 'VALUE '.$name.': '; $msg .= print_r($val, true); self::trace($msg, $calling_function_override); } public static function errLog($message) { $message = 'DUP:'.$message; error_log($message); } public static function TraceObject($msg, $o, $log_private_members = true) { if (self::$traceEnabled) { if (!$log_private_members) { $o = get_object_vars($o); } self::Trace($msg.':'.print_r($o, true)); } } public static function GetDefaultKey() { $auth_key = defined('AUTH_KEY') ? AUTH_KEY : 'atk'; $auth_key .= defined('DB_HOST') ? DB_HOST : 'dbh'; $auth_key .= defined('DB_NAME') ? DB_NAME : 'dbn'; $auth_key .= defined('DB_USER') ? DB_USER : 'dbu'; return hash('md5', $auth_key); } /** * Gets the current file size of the old trace file "1" * * @return string Returns a human readable file size of the active trace file */ public static function GetBackupTraceFilepath() { $default_key = self::getDefaultKey(); $backup_log_filename = "dup_$default_key.log1"; $backup_path = DUP_Settings::getSsdirPath()."/".$backup_log_filename; return $backup_path; } /** * Gets the active trace file path * * @return string Returns the full path to the active trace file (i.e. dup-pro_hash.log) */ public static function GetTraceFilepath() { $default_key = self::getDefaultKey(); $log_filename = "dup_$default_key.log"; $file_path = DUP_Settings::getSsdirPath()."/".$log_filename; return $file_path; } /** * Deletes the trace log and backup trace log files * * @return null */ public static function DeleteTraceLog() { $file_path = self::GetTraceFilepath(); $backup_path = self::GetBackupTraceFilepath(); self::trace("deleting $file_path"); @unlink($file_path); self::trace("deleting $backup_path"); @unlink($backup_path); } /** * Called when an error is detected and no further processing should occur * @param string $msg The message to log * @param string $detail Additional details to help resolve the issue if possible * @param int $behavior * @throws Exception */ public static function error($msg, $detail = '', $behavior = Dup_ErrorBehavior::Quit) { error_log($msg.' DETAIL:'.$detail); $source = self::getStack(debug_backtrace()); $err_msg = "\n==================================================================================\n"; $err_msg .= "DUPLICATOR ERROR\n"; $err_msg .= "Please try again! If the error persists see the Duplicator 'Help' menu.\n"; $err_msg .= "---------------------------------------------------------------------------------\n"; $err_msg .= "MESSAGE:\n\t{$msg}\n"; if (strlen($detail)) { $err_msg .= "DETAILS:\n\t{$detail}\n"; } $err_msg .= "TRACE:\n{$source}"; $err_msg .= "==================================================================================\n\n"; @fwrite(self::$logFileHandle, "{$err_msg}"); switch ($behavior) { case Dup_ErrorBehavior::ThrowException: DUP_LOG::trace("throwing exception"); throw new Exception($msg); break; case Dup_ErrorBehavior::Quit: DUP_LOG::trace("quitting"); die("DUPLICATOR ERROR: Please see the 'Package Log' file link below."); break; default: // Nothing } } /** * The current stack trace of a PHP call * @param $stacktrace The current debug stack * @return string */ public static function getStack($stacktrace) { $output = ""; $i = 1; foreach ($stacktrace as $node) { $output .= "\t $i. ".basename($node['file'])." : ".$node['function']." (".$node['line'].")\n"; $i++; } return $output; } /** * Manages writing the active or backup log based on the size setting * * @return null */ private static function WriteToTrace($formatted_logging_message) { $log_filepath = self::GetTraceFilepath(); if (@filesize($log_filepath) > DUPLICATOR_MAX_LOG_SIZE) { $backup_log_filepath = self::GetBackupTraceFilepath(); if (file_exists($backup_log_filepath)) { if (@unlink($backup_log_filepath) === false) { self::errLog("Couldn't delete backup log $backup_log_filepath"); } } if (@rename($log_filepath, $backup_log_filepath) === false) { self::errLog("Couldn't rename log $log_filepath to $backup_log_filepath"); } } if (@file_put_contents($log_filepath, $formatted_logging_message, FILE_APPEND) === false) { // Not en error worth reporting } } } class DUP_Handler { const MODE_OFF = 0; // don't write in log const MODE_LOG = 1; // write errors in log file const MODE_VAR = 2; // put php errors in $varModeLog static var const SHUTDOWN_TIMEOUT = 'tm'; /** * * @var bool */ private static $initialized = false; /** * * @var array */ private static $shutdownReturns = array( 'tm' => 'timeout' ); /** * * @var int */ private static $handlerMode = self::MODE_LOG; /** * * @var bool // print code reference and errno at end of php error line [CODE:10|FILE:test.php|LINE:100] */ private static $codeReference = true; /** * * @var bool // print prefix in php error line [PHP ERR][WARN] MSG: ..... */ private static $errPrefix = true; /** * * @var string // php errors in MODE_VAR */ private static $varModeLog = ''; /** * This function only initializes the error handler the first time it is called */ public static function init_error_handler() { if (!self::$initialized) { @set_error_handler(array(__CLASS__, 'error')); @register_shutdown_function(array(__CLASS__, 'shutdown')); self::$initialized = true; } } /** * Error handler * * @param integer $errno Error level * @param string $errstr Error message * @param string $errfile Error file * @param integer $errline Error line * @return void */ public static function error($errno, $errstr, $errfile, $errline) { switch (self::$handlerMode) { case self::MODE_OFF: if ($errno == E_ERROR) { $log_message = self::getMessage($errno, $errstr, $errfile, $errline); DUP_Log::error($log_message); } break; case self::MODE_VAR: self::$varModeLog .= self::getMessage($errno, $errstr, $errfile, $errline)."\n"; break; case self::MODE_LOG: default: switch ($errno) { case E_ERROR : $log_message = self::getMessage($errno, $errstr, $errfile, $errline); DUP_Log::error($log_message); break; case E_NOTICE : case E_WARNING : default : $log_message = self::getMessage($errno, $errstr, $errfile, $errline); DUP_Log::Info($log_message); break; } } } private static function getMessage($errno, $errstr, $errfile, $errline) { $result = ''; if (self::$errPrefix) { $result = '[PHP ERR]'; switch ($errno) { case E_ERROR : $result .= '[FATAL]'; break; case E_WARNING : $result .= '[WARN]'; break; case E_NOTICE : $result .= '[NOTICE]'; break; default : $result .= '[ISSUE]'; break; } $result .= ' MSG:'; } $result .= $errstr; if (self::$codeReference) { $result .= ' [CODE:'.$errno.'|FILE:'.$errfile.'|LINE:'.$errline.']'; $result .= "\n".wp_debug_backtrace_summary(); } return $result; } /** * if setMode is called without params set as default * * @param int $mode * @param bool $errPrefix // print prefix in php error line [PHP ERR][WARN] MSG: ..... * @param bool $codeReference // print code reference and errno at end of php error line [CODE:10|FILE:test.php|LINE:100] */ public static function setMode($mode = self::MODE_LOG, $errPrefix = true, $codeReference = true) { switch ($mode) { case self::MODE_OFF: case self::MODE_VAR: self::$handlerMode = $mode; break; case self::MODE_LOG: default: self::$handlerMode = self::MODE_LOG; } self::$varModeLog = ''; self::$errPrefix = $errPrefix; self::$codeReference = $codeReference; } /** * * @return string // return var log string in MODE_VAR */ public static function getVarLog() { return self::$varModeLog; } /** * * @return string // return var log string in MODE_VAR and clean var */ public static function getVarLogClean() { $result = self::$varModeLog; self::$varModeLog = ''; return $result; } /** * * @param string $status // timeout * @param string */ public static function setShutdownReturn($status, $str) { self::$shutdownReturns[$status] = $str; } /** * Shutdown handler * * @return void */ public static function shutdown() { if (($error = error_get_last())) { if (preg_match('/^Maximum execution time (?:.+) exceeded$/i', $error['message'])) { echo self::$shutdownReturns[self::SHUTDOWN_TIMEOUT]; } self::error($error['type'], $error['message'], $error['file'], $error['line']); } } } utilities/class.u.shell.php 0000644 00000002452 15133151516 0011752 0 ustar 00 <?php defined('ABSPATH') || defined('DUPXABSPATH') || exit; // Exit if accessed directly if (! defined('DUPLICATOR_VERSION')) exit; class DUP_Shell_U { /** * Escape a string to be used as a shell argument with bypass support for Windows * * NOTES: * Provides a way to support shell args on Windows OS and allows %,! on Windows command line * Safe if input is know such as a defined constant and not from user input escape shellarg * on Windows with turn %,! into spaces * * @return string */ public static function escapeshellargWindowsSupport($string) { if (strncasecmp(PHP_OS, 'WIN', 3) == 0) { if (strstr($string, '%') || strstr($string, '!')) { $result = '"'.str_replace('"', '', $string).'"'; return $result; } } return escapeshellarg($string); } /** * * @return boolean * */ public static function isPopenEnabled() { if (!DUP_Util::isIniFunctionEnalbe('popen') || !DUP_Util::isIniFunctionEnalbe('proc_open')) { $ret = false; } else { $ret = true; } $ret = apply_filters('duplicator_is_popen_enabled', $ret); return $ret; } } utilities/class.u.zip.php 0000644 00000013646 15133151516 0011454 0 ustar 00 <?php defined('ABSPATH') || defined('DUPXABSPATH') || exit; /** * Utility class for zipping up content * * Standard: PSR-2 * @link http://www.php-fig.org/psr/psr-2 * * @subpackage classes/utilities * @copyright (c) 2017, Snapcreek LLC * @license https://opensource.org/licenses/GPL-3.0 GNU Public License */ // Exit if accessed directly if (! defined('DUPLICATOR_VERSION')) exit; class DUP_Zip_U { /** * Add a directory to an existing ZipArchive object * * @param ZipArchive $zipArchive An existing ZipArchive object * @param string $directoryPath The full directory path to add to the ZipArchive * @param bool $retainDirectory Should the full directory path be retained in the archive * * @return bool Returns true if the directory was added to the object */ public static function addDirWithZipArchive(&$zipArchive, $directoryPath, $retainDirectory, $localPrefix, $isCompressed) { $success = TRUE; $directoryPath = rtrim($directoryPath, '/\\').'/'; if (!$fp = @opendir($directoryPath)) { return FALSE; } while (FALSE !== ($file = readdir($fp))) { if ($file === '.' || $file === '..') continue; $objectPath = $directoryPath . $file; // Not used DUP_U::safePath(), because I would like to decrease max_nest_level // Otherwise we will get the error: // PHP Fatal error: Uncaught Error: Maximum function nesting level of '512' reached, aborting! in ... // $objectPath = DUP_U::safePath($objectPath); $objectPath = str_replace("\\", '/', $objectPath); $localName = ltrim(str_replace($directoryPath, '', $objectPath), '/'); if ($retainDirectory) { $localName = basename($directoryPath)."/$localName"; } $localName = $localPrefix . $localName; if (is_dir($objectPath)) { $localPrefixArg = substr($localName, 0, strrpos($localName, '/')).'/'; $added = self::addDirWithZipArchive($zipArchive, $objectPath, $retainDirectory, $localPrefixArg, $isCompressed); } else if (is_readable($objectPath)) { $added = DUP_Zip_U::addFileToZipArchive($zipArchive, $objectPath, $localName, $isCompressed); } else { $added = FALSE; } if (!$added) { DUP_Log::error("Couldn't add file $objectPath to archive", '', false); $success = FALSE; break; } } @closedir($fp); return $success; } public static function extractFiles($archiveFilepath, $relativeFilesToExtract, $destinationDirectory, $useShellUnZip) { // TODO: Unzip using either shell unzip or ziparchive if($useShellUnZip) { $shellExecPath = DUPX_Server::get_unzip_filepath(); $filenameString = implode(' ', $relativeFilesToExtract); $command = "{$shellExecPath} -o -qq \"{$archiveFilepath}\" {$filenameString} -d {$destinationDirectory} 2>&1"; $stderr = shell_exec($command); if ($stderr != '') { $errorMessage = DUP_U::__("Error extracting {$archiveFilepath}): {$stderr}"); throw new Exception($errorMessage); } } else { $zipArchive = new ZipArchive(); $result = $zipArchive->open($archiveFilepath); if($result !== true) { throw new Exception("Error opening {$archiveFilepath} when extracting. Error code: {$retVal}"); } $result = $zipArchive->extractTo($destinationDirectory, $relativeFilesToExtract); if($result === false) { throw new Exception("Error extracting {$archiveFilepath}."); } } } /** * Add a directory to an existing ZipArchive object * * @param string $sourceFilePath The file to add to the zip file * @param string $zipFilePath The zip file to be added to * @param bool $deleteOld Delete the zip file before adding a file * @param string $newName Rename the $sourceFile if needed * * @return bool Returns true if the file was added to the zip file */ public static function zipFile($sourceFilePath, $zipFilePath, $deleteOld, $newName, $isCompressed) { if ($deleteOld && file_exists($zipFilePath)) { DUP_IO::deleteFile($zipFilePath); } if (file_exists($sourceFilePath)) { $zip_archive = new ZipArchive(); $is_zip_open = ($zip_archive->open($zipFilePath, ZIPARCHIVE::CREATE) === TRUE); if ($is_zip_open === false) { DUP_Log::error("Cannot create zip archive {$zipFilePath}"); } else { //ADD SQL if ($newName == null) { $source_filename = basename($sourceFilePath); DUP_Log::Info("adding {$source_filename}"); } else { $source_filename = $newName; DUP_Log::Info("new name added {$newName}"); } $in_zip = DUP_Zip_U::addFileToZipArchive($zip_archive, $sourceFilePath, $source_filename, $isCompressed); if ($in_zip === false) { DUP_Log::error("Unable to add {$sourceFilePath} to $zipFilePath"); } $zip_archive->close(); return true; } } else { DUP_Log::error("Trying to add {$sourceFilePath} to a zip but it doesn't exist!"); } return false; } public static function addFileToZipArchive(&$zipArchive, $filepath, $localName, $isCompressed) { $added = $zipArchive->addFile($filepath, $localName); return $added; } } utilities/class.u.string.php 0000644 00000006011 15133151516 0012144 0 ustar 00 <?php defined('ABSPATH') || defined('DUPXABSPATH') || exit; /** * Utility class working with strings * * Standard: PSR-2 * @link http://www.php-fig.org/psr/psr-2 * * @package DUP * @subpackage classes/utilities * @copyright (c) 2017, Snapcreek LLC * @license https://opensource.org/licenses/GPL-3.0 GNU Public License * */ class DUP_STR { /** * Append the value to the string if it doesn't already exist * * @param string $string The string to append to * @param string $value The string to append to the $string * * @return string Returns the string with the $value appended once */ public static function appendOnce($string, $value) { return $string.(substr($string, -1) == $value ? '' : $value); } /** * Returns true if the string contains UTF8 characters * @see http://php.net/manual/en/function.mb-detect-encoding.php * * @param string $string The class name where the $destArray exists * * @return null */ public static function hasUTF8($string) { return preg_match('%(?: [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte |\xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs |[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte |\xED[\x80-\x9F][\x80-\xBF] # excluding surrogates |\xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3 |[\xF1-\xF3][\x80-\xBF]{3} # planes 4-15 |\xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16 )+%xs', $string); } /** * Returns true if the $needle is found in the $haystack * * @param string $haystack The full string to search in * @param string $needle The string to for * * @return bool */ public static function contains($haystack, $needle) { $pos = strpos($haystack, $needle); return ($pos !== false); } /** * Returns true if the $haystack string starts with the $needle * * @param string $haystack The full string to search in * @param string $needle The string to for * * @return bool Returns true if the $haystack string starts with the $needle */ public static function startsWith($haystack, $needle) { $length = strlen($needle); return (substr($haystack, 0, $length) === $needle); } /** * Returns true if the $haystack string ends with the $needle * * @param string $haystack The full string to search in * @param string $needle The string to for * * @return bool Returns true if the $haystack string ends with the $needle */ public static function endsWith($haystack, $needle) { $length = strlen($needle); if ($length == 0) { return true; } return (substr($haystack, -$length) === $needle); } } utilities/class.u.multisite.php 0000644 00000001613 15133151516 0012660 0 ustar 00 <?php defined('ABSPATH') || defined('DUPXABSPATH') || exit; /** * Methods used to work with WordPress MU sites * * Standard: PSR-2 * @link http://www.php-fig.org/psr/psr-2 * * @package Duplicator * @subpackage classes/utilities * @copyright (c) 2017, Snapcreek LLC * * @todo Refactor out IO methods into class.io.php file */ // Exit if accessed directly if (! defined('DUPLICATOR_VERSION')) exit; class DUP_MU { public static function isMultisite() { return self::getMode() > 0; } // 0 = single site; 1 = multisite subdomain; 2 = multisite subdirectory public static function getMode() { if(is_multisite()) { if (defined('SUBDOMAIN_INSTALL') && SUBDOMAIN_INSTALL) { return 1; } else { return 2; } } else { return 0; } } } utilities/class.u.validator.php 0000644 00000013417 15133151516 0012633 0 ustar 00 <?php defined('ABSPATH') || defined('DUPXABSPATH') || exit; /** * Validate variables * * Standard: PSR-2 * @link http://www.php-fig.org/psr/psr-2 * * @package Duplicator * @subpackage classes/utilities * @copyright (c) 2017, Snapcreek LLC * */ // Exit if accessed directly if (!defined('DUPLICATOR_VERSION')) { exit; } class DUP_Validator { /** * @var array $patterns */ private static $patterns = array( 'fdir' => '/^([a-zA-Z]:[\\\\\/]|\/|\\\\\\\\|\/\/)[^<>\0]+$/', 'ffile' => '/^([a-zA-Z]:[\\\\\/]|\/|\\\\\\\\|\/\/)[^<>\0]+$/', 'fext' => '/^\.?[^\\\\\/*:<>\0?"|\s\.]+$/', 'email' => '/^[a-zA-Z0-9.!#$%&\'*+\/=?^_\`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/', 'empty' => '/^$/', 'nempty' => '/^.+$/', ); const FILTER_VALIDATE_IS_EMPTY = 'empty'; const FILTER_VALIDATE_NOT_EMPTY = 'nempty'; const FILTER_VALIDATE_FILE = 'ffile'; const FILTER_VALIDATE_FOLDER = 'fdir'; const FILTER_VALIDATE_FILE_EXT = 'fext'; const FILTER_VALIDATE_EMAIL = 'email'; /** * @var array $errors [ ['key' => string field key, * 'msg' => error message ] , [] ] */ private $errors = array(); /** * */ public function __construct() { $this->errors = array(); } /** * */ public function reset() { $this->errors = array(); } /** * * @return bool */ public function isSuccess() { return empty($this->errors); } /** * * @return array */ public function getErrors() { return $this->errors; } /** * * @return array return errors messages */ public function getErrorsMsg() { $result = array(); foreach ($this->errors as $err) { $result[] = $err['msg']; } return $result; } /** * * @param string $format printf format message where %s is the variable content default "%s\n" * @param bool $echo if false return string * @return void|string */ public function getErrorsFormat($format = "%s\n", $echo = true) { $msgs = $this->getErrorsMsg(); ob_start(); foreach ($msgs as $msg) { printf($format, $msg); } if ($echo) { ob_end_flush(); } else { return ob_get_clean(); } } /** * * @param string $key * @param string $msg */ protected function addError($key, $msg) { $this->errors[] = array( 'key' => $key, 'msg' => $msg ); } /** * filter_var function wrapper see http://php.net/manual/en/function.filter-var.php * * additional options * valkey => key of field * errmsg => error message; % s will be replaced with the contents of the variable es. "<b>%s</b> isn't a valid field" * acc_vals => array of accepted values that skip validation * * @param mixed $variable * @param int $filter * @param array $options * @return mixed */ public function filter_var($variable, $filter = FILTER_DEFAULT, $options = array()) { $success = true; $result = null; if (isset($options['acc_vals']) && in_array($variable, $options['acc_vals'])) { return $variable; } if ($filter === FILTER_VALIDATE_BOOLEAN) { $options['flags'] = FILTER_NULL_ON_FAILURE; $result = filter_var($variable, $filter, $options); if (is_null($result)) { $success = false; } } else { $result = filter_var($variable, $filter, $options); if ($result === false) { $success = false; } } if (!$success) { $key = isset($options['valkey']) ? $options['valkey'] : ''; if (isset($options['errmsg'])) { $msg = sprintf($options['errmsg'], $variable); } else { $msg = sprintf('%1$s isn\'t a valid value', $variable); } $this->addError($key, $msg); } return $result; } /** * validation of predefined regular expressions * * @param mixed $variable * @param string $filter * @param array $options * @return type * @throws Exception */ public function filter_custom($variable, $filter, $options = array()) { if (!isset(self::$patterns[$filter])) { throw new Exception('Filter not valid'); } $options = array_merge($options, array( 'options' => array( 'regexp' => self::$patterns[$filter]) ) ); //$options['regexp'] = self::$patterns[$filter]; return $this->filter_var($variable, FILTER_VALIDATE_REGEXP, $options); } /** * it explodes a string with a delimiter and validates every element of the array * * @param string $variable * @param string $delimiter * @param string $filter * @param array $options */ public function explode_filter_custom($variable, $delimiter, $filter, $options = array()) { if (empty($variable)) { return array(); } $vals = explode($delimiter, trim($variable, $delimiter)); $res = array(); foreach ($vals as $val) { $res[] = $this->filter_custom($val, $filter, $options); } return $res; } } utilities/class.u.json.php 0000644 00000011340 15133151516 0011610 0 ustar 00 <?php defined('ABSPATH') || defined('DUPXABSPATH') || exit; /** * Utility class for working with JSON data * * Standard: PSR-2 * @link http://www.php-fig.org/psr/psr-2 * * @subpackage classes/utilities * @copyright (c) 2017, Snapcreek LLC * @license https://opensource.org/licenses/GPL-3.0 GNU Public License */ // Exit if accessed directly if (! defined('DUPLICATOR_VERSION')) exit; class DUP_JSON { protected static $_messages = array( JSON_ERROR_NONE => 'No error has occurred', JSON_ERROR_DEPTH => 'The maximum stack depth has been exceeded', JSON_ERROR_STATE_MISMATCH => 'Invalid or malformed JSON', JSON_ERROR_CTRL_CHAR => 'Control character error, possibly incorrectly encoded', JSON_ERROR_SYNTAX => 'Syntax error', JSON_ERROR_UTF8 => 'Malformed UTF-8 characters. To resolve see https://snapcreek.com/duplicator/docs/faqs-tech/?utm_source=duplicator_free&utm_medium=wordpress_plugin&utm_campaign=problem_resolution&utm_content=malformed_utf8#faq-package-170-q' ); /** * Used on PHP 5.3+ to better handle calling the json_encode method * * Returns a string containing the JSON representation of the supplied value * * @return string */ public static function customEncode($value, $iteration = 1) { if (DUP_Util::$on_php_53_plus) { $encoded = DupLiteSnapJsonU::wp_json_encode_pprint($value); switch (json_last_error()) { case JSON_ERROR_NONE: return $encoded; case JSON_ERROR_DEPTH: throw new RuntimeException('Maximum stack depth exceeded'); case JSON_ERROR_STATE_MISMATCH: throw new RuntimeException('Underflow or the modes mismatch'); case JSON_ERROR_CTRL_CHAR: throw new RuntimeException('Unexpected control character found'); case JSON_ERROR_SYNTAX: throw new RuntimeException('Syntax error, malformed JSON'); case JSON_ERROR_UTF8: if ($iteration == 1) { $clean = self::makeUTF8($value); return self::customEncode($clean, $iteration + 1); } else { throw new RuntimeException('UTF-8 error loop'); } default: throw new RuntimeException('Unknown error'); } } else { return self::oldCustomEncode($value); } } public static function safeEncode($data, $options = 0, $depth = 512) { try { $jsonString = DupLiteSnapJsonU::wp_json_encode($data, $options, $depth); } catch (Exception $e) { $jsonString = false; } if (($jsonString === false) || trim($jsonString) == '') { $jsonString = self::customEncode($value); if (($jsonString === false) || trim($jsonString) == '') { throw new Exception('Unable to generate JSON from object'); } } return $jsonString; } /** * Attempts to only call the json_decode method directly * * Returns the value encoded in json in appropriate PHP type. Values true, false and null are returned as TRUE, FALSE and NULL respectively. * NULL is returned if the json cannot be decoded or if the encoded data is deeper than the recursion limit. * * @return object */ public static function decode($json, $assoc = false) { $result = json_decode($json, $assoc); if ($result !== null) { return $result; } if (function_exists('json_last_error')) { throw new RuntimeException(self::$_messages[json_last_error()]); } else { throw new RuntimeException("DUP_JSON decode error"); } } private static function makeUTF8($mixed) { if (is_array($mixed)) { foreach ($mixed as $key => $value) { $mixed[$key] = self::makeUTF8($value); } } else if (is_string($mixed)) { return utf8_encode($mixed); } return $mixed; } private static function escapeString($str) { return addcslashes($str, "\v\t\n\r\f\"\\/"); } private static function oldCustomEncode($in) { $out = ""; if (is_object($in)) { $arr[$key] = "\"".self::escapeString($key)."\":\"{$val}\""; $in = get_object_vars($in); } if (is_array($in)) { $obj = false; $arr = array(); foreach ($in AS $key => $val) { if (!is_numeric($key)) { $obj = true; } $arr[$key] = self::oldCustomEncode($val); } if ($obj) { foreach ($arr AS $key => $val) { $arr[$key] = "\"".self::escapeString($key)."\":{$val}"; } $val = implode(',', $arr); $out .= "{{$val}}"; } else { $val = implode(',', $arr); $out .= "[{$val}]"; } } elseif (is_bool($in)) { $out .= $in ? 'true' : 'false'; } elseif (is_null($in)) { $out .= 'null'; } elseif (is_string($in)) { $out .= "\"".self::escapeString($in)."\""; } else { $out .= $in; } return "{$out}"; } } utilities/class.u.migration.php 0000644 00000011532 15133151516 0012633 0 ustar 00 <?php /** * Utility class managing th emigration data * * Standard: PSR_2 * @link http://www.php_fig.org/psr/psr_2 * @copyright (c) 2017, Snapcreek LLC * @license https://opensource.org/licenses/GPL_3.0 GNU Public License * */ defined('ABSPATH') || defined('DUPXABSPATH') || exit; class DUP_Migration { const CLEAN_INSTALL_REPORT_OPTION = 'duplicator_clean_install_report'; const ARCHIVE_REGEX_PATTERN = '/^(.+_[a-z0-9]{7,}_[0-9]{14})_archive\.(?:zip|daf)$/'; /** * messages to be displayed in the successful migration box * * @var array */ protected static $migrationCleanupReport = array( 'removed' => array(), 'stored' => array(), 'instFile' => array() ); /** * Check the root path and in case there are installer files without hashes rename them. * * @return void */ public static function renameInstallersPhpFiles() { $pathsTocheck = array( DupLiteSnapLibIOU::safePathTrailingslashit(ABSPATH), DupLiteSnapLibIOU::safePathTrailingslashit(DupLiteSnapLibUtilWp::getHomePath()), DupLiteSnapLibIOU::safePathTrailingslashit(WP_CONTENT_DIR) ); $pathsTocheck = array_unique($pathsTocheck); $filesToCheck = array(); foreach ($pathsTocheck as $cFolder) { if ( !is_dir($cFolder) || !is_writable($cFolder) // rename permissions ) { continue; } $cFile = $cFolder . 'installer.php'; if ( !is_file($cFile) || !DupLiteSnapLibIOU::chmod($cFile, 'u+rw') || !is_readable($cFile) ) { continue; } $filesToCheck[] = $cFile; } $installerTplCheck = '/class DUPX_Bootstrap.+const\s+ARCHIVE_FILENAME\s*=\s*[\'"](.+?)[\'"]\s*;.*const\s+PACKAGE_HASH\s*=\s*[\'"](.+?)[\'"];/s'; foreach ($filesToCheck as $file) { $fileName = basename($file); if (($content = @file_get_contents($file, false, null, 0, 5000)) === false) { continue; } $matches = null; if (preg_match($installerTplCheck, $content, $matches) !== 1) { continue; } $archiveName = $matches[1]; $hash = $matches[2]; $matches = null; if (preg_match(self::ARCHIVE_REGEX_PATTERN, $archiveName, $matches) !== 1) { if (DupLiteSnapLibIOU::unlink($file)) { self::$migrationCleanupReport['instFile'][] = "<div class='failure'>" . "<i class='fa fa-check green'></i> " . sprintf(__('Installer file <b>%s</b> removed for secority reasons', 'duplicator'), esc_html($fileName)) . "</div>"; } else { self::$migrationCleanupReport['instFile'][] = "<div class='success'>" . '<i class="fa fa-exclamation-triangle red"></i> ' . sprintf(__('Can\'t remove installer file <b>%s</b>, please remove it for security reasons', 'duplicator'), esc_html($fileName)) . '</div>'; } continue; } $archiveHash = $matches[1]; if (strpos($file, $archiveHash) === false) { if (DupLiteSnapLibIOU::rename($file, dirname($file) . '/' . $archiveHash . '_installer.php', true)) { self::$migrationCleanupReport['instFile'][] = "<div class='failure'>" . "<i class='fa fa-check green'></i> " . sprintf(__('Installer file <b>%s</b> renamed with HASH', 'duplicator'), esc_html($fileName)) . "</div>"; } else { self::$migrationCleanupReport['instFile'][] = "<div class='success'>" . '<i class="fa fa-exclamation-triangle red"></i> ' . sprintf(__('Can\'t rename installer file <b>%s</b> with HASH, please remove it for security reasons', 'duplicator'), esc_html($fileName)) . '</div>'; } } } } /** * return cleanup report * * @return array */ public static function getCleanupReport() { $option = get_option(self::CLEAN_INSTALL_REPORT_OPTION); if (is_array($option)) { self::$migrationCleanupReport = array_merge(self::$migrationCleanupReport, $option); } return self::$migrationCleanupReport; } /** * save clean up report in wordpress options * * @return boolean */ public static function saveCleanupReport() { return add_option(self::CLEAN_INSTALL_REPORT_OPTION, self::$migrationCleanupReport, '', 'no'); } } utilities/class.u.php 0000644 00000063456 15133151516 0010657 0 ustar 00 <?php defined('ABSPATH') || defined('DUPXABSPATH') || exit; /** * Recursivly scans a directory and finds all sym-links and unreadable files * * Standard: PSR-2 * @link http://www.php-fig.org/psr/psr-2 * * @package Duplicator * @subpackage classes/utilities * @copyright (c) 2017, Snapcreek LLC * * @todo Refactor out IO methods into class.io.php file */ class DUP_Util { /** * Is PHP 5.2.9 or better running */ public static $on_php_529_plus; /** * Is PHP 5.3 or better running */ public static $on_php_53_plus; /** * Is PHP 5.4 or better running */ public static $on_php_54_plus; /** * Is PHP 7 or better running */ public static $PHP7_plus; /** * array of ini disable functions * * @var array */ private static $iniDisableFuncs = null; /** * Initialized on load (see end of file) */ public static function init() { self::$on_php_529_plus = version_compare(PHP_VERSION, '5.2.9') >= 0; self::$on_php_53_plus = version_compare(PHP_VERSION, '5.3.0') >= 0; self::$on_php_54_plus = version_compare(PHP_VERSION, '5.4.0') >= 0; self::$PHP7_plus = version_compare(PHP_VERSION, '7.0.0', '>='); } public static function getArchitectureString() { $php_int_size = PHP_INT_SIZE; switch ($php_int_size) { case 4: return esc_html__('32-bit', 'duplicator'); break; case 8: return esc_html__('64-bit', 'duplicator'); break; default: return esc_html__('Unknown', 'duplicator'); } } public static function objectCopy($srcObject, $destObject, $skipMemberArray = null) { foreach ($srcObject as $member_name => $member_value) { if (!is_object($member_value) && (($skipMemberArray == null) || !in_array($member_name, $skipMemberArray))) { // Skipping all object members $destObject->$member_name = $member_value; } } } public static function getWPCoreDirs() { $wp_core_dirs = array(get_home_path().'wp-admin', get_home_path().'wp-includes'); //if wp_content is overrided $wp_path = get_home_path()."wp-content"; if (get_home_path().'wp-content' != WP_CONTENT_DIR) { $wp_path = WP_CONTENT_DIR; } $wp_path = str_replace("\\", "/", $wp_path); $wp_core_dirs[] = $wp_path; $wp_core_dirs[] = $wp_path.'/plugins'; $wp_core_dirs[] = $wp_path.'/themes'; return $wp_core_dirs; } /** * return absolute path for the files that are core directories * @return string array */ public static function getWPCoreFiles() { $wp_cored_dirs = array(get_home_path().'wp-config.php'); return $wp_cored_dirs; } /** * Groups an array into arrays by a given key, or set of keys, shared between all array members. * * Based on {@author Jake Zatecky}'s {@link https://github.com/jakezatecky/array_group_by array_group_by()} function. * This variant allows $key to be closures. * * @param array $array The array to have grouping performed on. * @param mixed $key,... The key to group or split by. Can be a _string_, an _integer_, a _float_, or a _callable_. * - If the key is a callback, it must return a valid key from the array. * - If the key is _NULL_, the iterated element is skipped. * - string|oink callback ( mixed $item ) * * @return array|null Returns a multidimensional array or `null` if `$key` is invalid. */ public static function array_group_by(array $array, $key) { if (!is_string($key) && !is_int($key) && !is_float($key) && !is_callable($key)) { trigger_error('array_group_by(): The key should be a string, an integer, or a callback', E_USER_ERROR); return null; } $func = (!is_string($key) && is_callable($key) ? $key : null); $_key = $key; // Load the new array, splitting by the target key $grouped = array(); foreach ($array as $value) { $key = null; if (is_callable($func)) { $key = call_user_func($func, $value); } elseif (is_object($value) && isset($value->{$_key})) { $key = $value->{$_key}; } elseif (isset($value[$_key])) { $key = $value[$_key]; } if ($key === null) { continue; } $grouped[$key][] = $value; } // Recursively build a nested grouping if more parameters are supplied // Each grouped array value is grouped according to the next sequential key if (func_num_args() > 2) { $args = func_get_args(); foreach ($grouped as $key => $value) { $params = array_merge(array($value), array_slice($args, 2, func_num_args())); $grouped[$key] = call_user_func_array('DUP_Util::array_group_by', $params); } } return $grouped; } /** * PHP_SAPI for FCGI requires a data flush of at least 256 * bytes every 40 seconds or else it forces a script halt * * @return string A series of 256 space characters */ public static function fcgiFlush() { echo(str_repeat(' ', 300)); @flush(); @ob_flush(); } public static function isWpDebug() { return defined('WP_DEBUG') && WP_DEBUG; } /** * Returns the last N lines of a file. Equivalent to tail command * * @param string $filepath The full path to the file to be tailed * @param int $lines The number of lines to return with each tail call * * @return string The last N parts of the file */ public static function tailFile($filepath, $lines = 2) { // Open file $f = @fopen($filepath, "rb"); if ($f === false) return false; // Sets buffer size $buffer = 256; // Jump to last character fseek($f, -1, SEEK_END); // Read it and adjust line number if necessary // (Otherwise the result would be wrong if file doesn't end with a blank line) if (fread($f, 1) != "\n") $lines -= 1; // Start reading $output = ''; $chunk = ''; // While we would like more while (ftell($f) > 0 && $lines >= 0) { // Figure out how far back we should jump $seek = min(ftell($f), $buffer); // Do the jump (backwards, relative to where we are) fseek($f, -$seek, SEEK_CUR); // Read a chunk and prepend it to our output $output = ($chunk = fread($f, $seek)).$output; // Jump back to where we started reading fseek($f, -mb_strlen($chunk, '8bit'), SEEK_CUR); // Decrease our line counter $lines -= substr_count($chunk, "\n"); } // While we have too many lines // (Because of buffer size we might have read too many) while ($lines++ < 0) { // Find first newline and remove all text before that $output = substr($output, strpos($output, "\n") + 1); } fclose($f); return trim($output); } /** * Display human readable byte sizes * * @param int $size The size in bytes * * @return string The size of bytes readable such as 100KB, 20MB, 1GB etc. */ public static function byteSize($size, $roundBy = 2) { try { $units = array('B', 'KB', 'MB', 'GB', 'TB'); for ($i = 0; $size >= 1024 && $i < 4; $i++) { $size /= 1024; } return round($size, $roundBy).$units[$i]; } catch (Exception $e) { return "n/a"; } } /** * Makes path safe for any OS * Paths should ALWAYS READ be "/" * uni: /home/path/file.txt * win: D:/home/path/file.txt * * @param string $path The path to make safe * * @return string A path with all slashes facing "/" */ public static function safePath($path) { return str_replace("\\", "/", $path); } /** * Get current microtime as a float. Method is used for simple profiling * * @see elapsedTime * * @return string A float in the form "msec sec", where sec is the number of seconds since the Unix epoch */ public static function getMicrotime() { return microtime(true); } /** * Append the value to the string if it doesn't already exist * * @param string $string The string to append to * @param string $value The string to append to the $string * * @return string Returns the string with the $value appended once */ public static function appendOnce($string, $value) { return $string.(substr($string, -1) == $value ? '' : $value); } /** * Return a string with the elapsed time * * @see getMicrotime() * * @param mixed number $end The final time in the sequence to measure * @param mixed number $start The start time in the sequence to measure * * @return string The time elapsed from $start to $end */ public static function elapsedTime($end, $start) { return sprintf("%.2f sec.", abs($end - $start)); } /** * List all of the files of a path * * @param string $path The full path to a system directory * * @return array of all files in that path * * Notes: * - Avoid using glob() as GLOB_BRACE is not an option on some operating systems * - Pre PHP 5.3 DirectoryIterator will crash on unreadable files * - Scandir will not crash on unreadable items, but will not return results */ public static function listFiles($path = '.') { try { $files = array(); if ($dh = opendir($path)) { while (($file = readdir($dh)) !== false) { if ($file == '.' || $file == '..') continue; $full_file_path = trailingslashit($path).$file; $files[] = str_replace("\\", '/', $full_file_path); } @closedir($dh); } return $files; } catch (Exception $exc) { $result = array(); $files = @scandir($path); if (is_array($files)) { foreach ($files as $file) { $result[] = str_replace("\\", '/', $path).$file; } } return $result; } } /** * List all of the directories of a path * * @param string $path The full path to a system directory * * @return array of all dirs in the $path */ public static function listDirs($path = '.') { $dirs = array(); foreach (new DirectoryIterator($path) as $file) { if ($file->isDir() && !$file->isDot()) { $dirs[] = DUP_Util::safePath($file->getPathname()); } } return $dirs; } /** * Does the directory have content * * @param string $path The full path to a system directory * * @return bool Returns true if directory is empty */ public static function isDirectoryEmpty($path) { if (!is_readable($path)) return NULL; return (count(scandir($path)) == 2); } /** * Size of the directory recursively in bytes * * @param string $path The full path to a system directory * * @return int Returns the size of the directory in bytes * */ public static function getDirectorySize($path) { if (!file_exists($path)) return 0; if (is_file($path)) return filesize($path); $size = 0; $list = glob($path."/*"); if (!empty($list)) { foreach ($list as $file) $size += self::getDirectorySize($file); } return $size; } /** * Can shell_exec be called on this server * * @return bool Returns true if shell_exec can be called on server * */ public static function hasShellExec() { $cmds = array('shell_exec', 'escapeshellarg', 'escapeshellcmd', 'extension_loaded'); //Function disabled at server level if (array_intersect($cmds, array_map('trim', explode(',', @ini_get('disable_functions'))))) return apply_filters('duplicator_is_shellzip_available', false); //Suhosin: http://www.hardened-php.net/suhosin/ //Will cause PHP to silently fail if (extension_loaded('suhosin')) { $suhosin_ini = @ini_get("suhosin.executor.func.blacklist"); if (array_intersect($cmds, array_map('trim', explode(',', $suhosin_ini)))) return apply_filters('duplicator_is_shellzip_available', false); } if (! function_exists('shell_exec')) { return apply_filters('duplicator_is_shellzip_available', false); } // Can we issue a simple echo command? if (!@shell_exec('echo duplicator')) return apply_filters('duplicator_is_shellzip_available', false); return apply_filters('duplicator_is_shellzip_available', true); } /** * Is the server running Windows operating system * * @return bool Returns true if operating system is Windows * */ public static function isWindows() { if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { return true; } return false; } /** * Wrap to prevent malware scanners from reporting false/positive * Switched from our old method to avoid WordFence reporting a false positive * * @param string $string The string to decrypt i.e. base64_decode * * @return string Returns the string base64 decoded */ public static function installerUnscramble($string) { return base64_decode($string); } /** * Wrap to prevent malware scanners from reporting false/positive * Switched from our old method to avoid WordFence reporting a false positive * * @param string $string The string to decrypt i.e. base64_encode * * @return string Returns the string base64 encode */ public static function installerScramble($string) { return base64_encode($string); } const SECURE_ISSUE_DIE = 'die'; const SECURE_ISSUE_THROW = 'throw'; const SECURE_ISSUE_RETURN = 'return'; /** * Does the current user have the capability * * @param type $permission * @param type $exit // SECURE_ISSUE_DIE die script with die function * SECURE_ISSUE_THROW throw an exception if fail * SECURE_ISSUE_RETURN return false if fail * * @return boolean // return false is fail and $exit is SECURE_ISSUE_THROW * // true if success * * @throws Exception // thow exception if $exit is SECURE_ISSUE_THROW */ public static function hasCapability($permission = 'read', $exit = self::SECURE_ISSUE_DIE) { $capability = apply_filters('wpfront_user_role_editor_duplicator_translate_capability', $permission); if (!current_user_can($capability)) { $exitMsg = __('You do not have sufficient permissions to access this page.', 'duplicator'); DUP_LOG::Trace('You do not have sufficient permissions to access this page. PERMISSION: '.$permission); switch ($exit) { case self::SECURE_ISSUE_THROW: throw new Exception($exitMsg); case self::SECURE_ISSUE_RETURN: return false; case self::SECURE_ISSUE_DIE: default: wp_die($exitMsg); } } return true; } /** * Gets the name of the owner of the current PHP script * * @return string The name of the owner of the current PHP script */ public static function getCurrentUser() { $unreadable = 'Undetectable'; if (function_exists('get_current_user') && is_callable('get_current_user')) { $user = get_current_user(); return strlen($user) ? $user : $unreadable; } return $unreadable; } /** * Gets the owner of the PHP process * * @return string Gets the owner of the PHP process */ public static function getProcessOwner() { $unreadable = 'Undetectable'; $user = ''; try { if (function_exists('exec')) { $user = @exec('whoami'); } if (!strlen($user) && function_exists('posix_getpwuid') && function_exists('posix_geteuid')) { $user = posix_getpwuid(posix_geteuid()); $user = $user['name']; } return strlen($user) ? $user : $unreadable; } catch (Exception $ex) { return $unreadable; } } /** * Creates the snapshot directory if it doesn't already exist * * @return bool */ public static function initSnapshotDirectory() { $error = false; $path_wproot = duplicator_get_abs_path(); $path_ssdir = DUP_Settings::getSsdirPath(); $path_plugin = DUP_Util::safePath(DUPLICATOR_PLUGIN_PATH); if (!file_exists($path_ssdir)) { $old_root_perm = @fileperms($path_wproot); //-------------------------------- //CHMOD DIRECTORY ACCESS //wordpress root directory DupLiteSnapLibIOU::chmod($path_wproot, 'u+rwx'); //snapshot directory if (DupLiteSnapLibIOU::dirWriteCheckOrMkdir($path_ssdir, 'u+rwx,go+rx') == false) { $error = true; } // restore original root perms DupLiteSnapLibIOU::chmod($path_wproot, $old_root_perm); if ($error) { return false; } } DupLiteSnapLibIOU::chmod($path_ssdir, 'u+rwx,go+rx'); DupLiteSnapLibIOU::dirWriteCheckOrMkdir(DUP_Settings::getSsdirTmpPath(), 'u+rwx'); //plugins dir/files DupLiteSnapLibIOU::dirWriteCheckOrMkdir($path_plugin.'files', 'u+rwx'); //-------------------------------- //FILE CREATION //SSDIR: Create Index File $fileName = $path_ssdir.'/index.php'; if (!file_exists($fileName)) { $ssfile = @fopen($fileName, 'w'); @fwrite($ssfile, '<?php error_reporting(0); if (stristr(php_sapi_name(), "fcgi")) { $url = "http://" . $_SERVER["HTTP_HOST"]; header("Location: {$url}/404.html");} else { header("HTTP/1.1 404 Not Found", true, 404);} exit(); ?>'); @fclose($ssfile); } //SSDIR: Create .htaccess $storage_htaccess_off = DUP_Settings::Get('storage_htaccess_off'); $fileName = $path_ssdir.'/.htaccess'; if ($storage_htaccess_off) { @unlink($fileName); } else if (!file_exists($fileName)) { $htfile = @fopen($fileName, 'w'); $htoutput = "Options -Indexes"; @fwrite($htfile, $htoutput); @fclose($htfile); } //SSDIR: Robots.txt file $fileName = $path_ssdir.'/robots.txt'; if (!file_exists($fileName)) { $robotfile = @fopen($fileName, 'w'); @fwrite($robotfile, "User-agent: * \n" ."Disallow: /".DUP_Settings::SSDIR_NAME_LEGACY."/\n" ."Disallow: /".DUP_Settings::SSDIR_NAME_NEW."/"); @fclose($robotfile); } return true; } /** * Attempts to get the file zip path on a users system * * @return null */ public static function getZipPath() { $filepath = null; if (self::hasShellExec()) { if (shell_exec('hash zip 2>&1') == NULL) { $filepath = 'zip'; } else { $possible_paths = array( '/usr/bin/zip', '/opt/local/bin/zip' //'C:/Program\ Files\ (x86)/GnuWin32/bin/zip.exe'); ); foreach ($possible_paths as $path) { if (@file_exists($path)) { $filepath = $path; break; } } } } return $filepath; } /** * Is the server PHP 5.3 or better * * @return bool Returns true if the server PHP 5.3 or better */ public static function PHP53() { return version_compare(PHP_VERSION, '5.3.2', '>='); } /** * Returns an array of the WordPress core tables. * * @return array Returns all WP core tables */ public static function getWPCoreTables() { global $wpdb; $result = array(); foreach (self::getWPCoreTablesEnd() as $tend) { $result[] = $wpdb->prefix.$tend; } return $result; } public static function getWPCoreTablesEnd() { return array( 'commentmeta', 'comments', 'links', 'options', 'postmeta', 'posts', 'term_relationships', 'term_taxonomy', 'termmeta', 'terms', 'usermeta', 'blogs', 'blog_versions', 'blogmeta', 'users', 'site', 'sitemeta', 'signups', 'registration_log', 'blog_versions'); } public static function isWPCoreTable($table) { global $wpdb; if (strpos($table, $wpdb->prefix) !== 0) { return false; } $subTName = substr($table, strlen($wpdb->prefix)); $coreEnds = self::getWPCoreTablesEnd(); if (in_array($subTName, $coreEnds)) { return true; } else if (is_multisite()) { $exTable = explode('_', $subTName); if (count($exTable) >= 2 && is_numeric($exTable[0])) { $tChekc = implode('_', array_slice($exTable, 1)); if (get_blog_details((int) $exTable[0], false) !== false && in_array($tChekc, $coreEnds)) { return true; } } } return false; } public static function getWPBlogIdTable($table) { global $wpdb; if (!is_multisite() || strpos($table, $wpdb->prefix) !== 0) { return 0; } $subTName = substr($table, strlen($wpdb->prefix)); $exTable = explode('_', $subTName); if (count($exTable) >= 2 && is_numeric($exTable[0]) && get_blog_details((int) $exTable[0], false) !== false) { return (int) $exTable[0]; } else { return 0; } } /** * Check given table is exist in real * * @param $table string Table name * @return booleam */ public static function isTableExists($table) { // It will clear the $GLOBALS['wpdb']->last_error var $GLOBALS['wpdb']->flush(); $sql = "SELECT 1 FROM `".esc_sql($table)."` LIMIT 1;"; $ret = $GLOBALS['wpdb']->get_var($sql); if (empty($GLOBALS['wpdb']->last_error)) return true; return false; } /** * Finds if its a valid executable or not * * @param type $exe A non zero length executable path to find if that is executable or not. * @param type $expectedValue expected value for the result * @return boolean */ public static function isExecutable($cmd) { if (strlen($cmd) < 1) return false; if (@is_executable($cmd)) { return true; } $output = shell_exec($cmd); if (!is_null($output)) { return true; } $output = shell_exec($cmd.' -?'); if (!is_null($output)) { return true; } return false; } /** * Display human readable byte sizes * * @param string $size The size in bytes * * @return string Human readable bytes such as 50MB, 1GB */ public static function readableByteSize($size) { try { $units = array('B', 'KB', 'MB', 'GB', 'TB'); for ($i = 0; $size >= 1024 && $i < 4; $i++) $size /= 1024; return round($size, 2).$units[$i]; } catch (Exception $e) { return "n/a"; } } public static function getTablePrefix() { global $wpdb; $tablePrefix = (is_multisite() && is_plugin_active_for_network('duplicator/duplicator.php')) ? $wpdb->base_prefix : $wpdb->prefix; return $tablePrefix; } /** * return ini disable functions array * * @return array */ public static function getIniDisableFuncs() { if (is_null(self::$iniDisableFuncs)) { $tmpFuncs = ini_get('disable_functions'); $tmpFuncs = explode(',', $tmpFuncs); self::$iniDisableFuncs = array(); foreach ($tmpFuncs as $cFunc) { self::$iniDisableFuncs[] = trim($cFunc); } } return self::$iniDisableFuncs; } /** * Check if function exists and isn't in ini disable_functions * * @param string $function_name * @return bool */ public static function isIniFunctionEnalbe($function_name) { return function_exists($function_name) && !in_array($function_name, self::getIniDisableFuncs()); } } utilities/class.u.scancheck.php 0000644 00000012073 15133151516 0012565 0 ustar 00 <?php defined('ABSPATH') || defined('DUPXABSPATH') || exit; /** * Recursivly scans a directory and finds all sym-links and unreadable files * * Standard: PSR-2 * @link http://www.php-fig.org/psr/psr-2 * * @package Duplicator * @subpackage classes/utilities * @copyright (c) 2017, Snapcreek LLC * */ // Exit if accessed directly if (! defined('DUPLICATOR_VERSION')) exit; class DUP_ScanCheck { /** * The number of files scanned */ public $fileCount = 0; /** * The number of directories scanned */ public $dirCount = 0; /** * The maximum count of files before the recursive function stops */ public $maxFiles = 1000000; /** * The maximum count of directories before the recursive function stops */ public $maxDirs = 75000; /** * Recursivly scan the root directory provided */ public $recursion = true; /** * Stores a list of symbolic link files */ public $symLinks = array(); /** * Stores a list of files unreadable by PHP */ public $unreadable = array(); /** * Stores a list of dirs with utf8 settings */ public $nameTestDirs = array(); /** * Stores a list of files with utf8 settings */ public $nameTestFiles = array(); /** * If the maxFiles or maxDirs limit is reached then true */ protected $limitReached = false; /** * Is the server running on Windows */ private $isWindows = false; /** * Init this instance of the object */ function __construct() { $this->isWindows = defined('PHP_WINDOWS_VERSION_BUILD'); } /** * Start the scan process * * @param string $dir A valid directory path where the scan will run * @param array $results Used for recursion, do not pass in value with calling * * @return obj The scan check object with the results of the scan */ public function run($dir, &$results = array()) { //Stop Recursion if Max search is reached if ($this->fileCount > $this->maxFiles || $this->dirCount > $this->maxDirs) { $this->limitReached = true; return $results; } $files = @scandir($dir); if (is_array($files)) { foreach ($files as $key => $value) { $path = realpath($dir.DIRECTORY_SEPARATOR.$value); if ($path) { //Files if (!is_dir($path)) { if (!is_readable($path)) { $results[] = $path; $this->unreadable[] = $path; } else if ($this->isLink($path)) { $results[] = $path; $this->symLinks[] = $path; } else { $name = basename($path); $invalid_test = preg_match('/(\/|\*|\?|\>|\<|\:|\\|\|)/', $name) || trim($name) == '' || (strrpos($name, '.') == strlen($name) - 1 && substr($name, -1) == '.') || preg_match('/[^\x20-\x7f]/', $name); if ($invalid_test) { if (! DUP_Util::$PHP7_plus && DUP_Util::isWindows()) { $this->nameTestFiles[] = utf8_decode($path); } else { $this->nameTestFiles[] = $path; } } } $this->fileCount++; } //Dirs else if ($value != "." && $value != "..") { if (!$this->isLink($path) && $this->recursion) { $this->Run($path, $results); } if (!is_readable($path)) { $results[] = $path; $this->unreadable[] = $path; } else if ($this->isLink($path)) { $results[] = $path; $this->symLinks[] = $path; } else { $invalid_test = strlen($path) > 244 || trim($path) == '' || preg_match('/[^\x20-\x7f]/', $path); if ($invalid_test) { if (! DUP_Util::$PHP7_plus && DUP_Util::isWindows()) { $this->nameTestDirs[] = utf8_decode($path); } else { $this->nameTestDirs[] = $path; } } } $this->dirCount++; } } } } return $this; } /** * Separation logic for supporting how different operating systems work * * @param string $target A valid file path * * @return bool Is the target a sym link */ private function isLink($target) { //Currently Windows does not support sym-link detection if ($this->isWindows) { return false; } elseif (is_link($target)) { return true; } return false; } } class.server.php 0000644 00000033424 15133151516 0007676 0 ustar 00 <?php defined('ABSPATH') || defined('DUPXABSPATH') || exit; require_once (DUPLICATOR_PLUGIN_PATH.'classes/utilities/class.u.php'); /** * Used to get various pieces of information about the server environment * * Standard: PSR-2 * @link http://www.php-fig.org/psr/psr-2 * * @package Duplicator * @subpackage classes/utilities * @copyright (c) 2017, Snapcreek LLC * */ class DUP_Server { const LockFileName = 'lockfile.txt'; // Possibly use in the future if we want to prevent double building public static function isEngineLocked() { if (self::setEngineLock(true)) { self::setEngineLock(false); $locked = false; } else { $locked = true; } } // Possibly use in the future if we want to prevent double building public static function setEngineLock($shouldLock) { $success = false; $locking_file = @fopen(self::LockFileName, 'c+'); if ($locking_file != false) { if ($shouldLock) { $success = @flock($locking_file, LOCK_EX | LOCK_NB); } else { $success = @flock($locking_file, LOCK_UN); } @fclose($locking_file); } return $success; } public static function mysqlEscapeIsOk() { $escape_test_string = chr(0).chr(26)."\r\n'\"\\"; $escape_expected_result = "\"\\0\Z\\r\\n\\'\\\"\\\\\""; $escape_actual_result = DUP_DB::escValueToQueryString($escape_test_string); $result = $escape_expected_result === $escape_actual_result; if (!$result) { $msg = "mysqli_real_escape_string test results\n". "Expected escape result: ".$escape_expected_result."\n". "Actual escape result: ".$escape_actual_result; DUP_Log::trace($msg); } return $result; } /** * Gets the system requirements which must pass to build a package * * @return array An array of requirements */ public static function getRequirements() { $dup_tests = array(); //PHP SUPPORT $safe_ini = strtolower(ini_get('safe_mode')); $dup_tests['PHP']['SAFE_MODE'] = $safe_ini != 'on' || $safe_ini != 'yes' || $safe_ini != 'true' || ini_get("safe_mode") != 1 ? 'Pass' : 'Fail'; self::logRequirementFail($dup_tests['PHP']['SAFE_MODE'], 'SAFE_MODE is on.'); $dup_tests['PHP']['VERSION'] = DUP_Util::$on_php_529_plus ? 'Pass' : 'Fail'; $phpversion = phpversion(); self::logRequirementFail($dup_tests['PHP']['VERSION'], 'PHP version('.$phpversion.') is lower than 5.2.9'); if (DUP_Settings::Get('archive_build_mode') == DUP_Archive_Build_Mode::ZipArchive) { $dup_tests['PHP']['ZIP'] = class_exists('ZipArchive') ? 'Pass' : 'Fail'; self::logRequirementFail($dup_tests['PHP']['ZIP'], 'ZipArchive class doesn\'t exist.'); } $dup_tests['PHP']['FUNC_1'] = function_exists("file_get_contents") ? 'Pass' : 'Fail'; self::logRequirementFail($dup_tests['PHP']['FUNC_1'], 'file_get_contents function doesn\'t exist.'); $dup_tests['PHP']['FUNC_2'] = function_exists("file_put_contents") ? 'Pass' : 'Fail'; self::logRequirementFail($dup_tests['PHP']['FUNC_2'], 'file_put_contents function doesn\'t exist.'); $dup_tests['PHP']['FUNC_3'] = function_exists("mb_strlen") ? 'Pass' : 'Fail'; self::logRequirementFail($dup_tests['PHP']['FUNC_3'], 'mb_strlen function doesn\'t exist.'); $dup_tests['PHP']['ALL'] = !in_array('Fail', $dup_tests['PHP']) ? 'Pass' : 'Fail'; //REQUIRED PATHS $abs_path = duplicator_get_abs_path(); $handle_test = @opendir($abs_path); $dup_tests['IO']['WPROOT'] = is_writeable($abs_path) && $handle_test ? 'Pass' : 'Warn'; @closedir($handle_test); self::logRequirementFail($dup_tests['IO']['WPROOT'], $abs_path.' (abs path) can\'t be opened.'); $dup_tests['IO']['SSDIR'] = is_writeable(DUP_Settings::getSsdirPath()) ? 'Pass' : 'Fail'; self::logRequirementFail($dup_tests['IO']['SSDIR'], DUP_Settings::getSsdirPath().' (DUPLICATOR_SSDIR_PATH) can\'t be writeable.'); $dup_tests['IO']['SSTMP'] = is_writeable(DUP_Settings::getSsdirTmpPath()) ? 'Pass' : 'Fail'; self::logRequirementFail($dup_tests['IO']['SSTMP'], DUP_Settings::getSsdirTmpPath().' (DUPLICATOR_SSDIR_PATH_TMP) can\'t be writeable.'); $dup_tests['IO']['ALL'] = !in_array('Fail', $dup_tests['IO']) ? 'Pass' : 'Fail'; //SERVER SUPPORT $dup_tests['SRV']['MYSQLi'] = function_exists('mysqli_connect') ? 'Pass' : 'Fail'; self::logRequirementFail($dup_tests['SRV']['MYSQLi'], 'mysqli_connect function doesn\'t exist.'); //mysqli_real_escape_string test $dup_tests['SRV']['MYSQL_ESC'] = self::mysqlEscapeIsOk() ? 'Pass' : 'Fail'; self::logRequirementFail($dup_tests['SRV']['MYSQL_ESC'], "The function mysqli_real_escape_string is not escaping strings as expected."); $db_version = DUP_DB::getVersion(); $dup_tests['SRV']['MYSQL_VER'] = version_compare($db_version, '5.0', '>=') ? 'Pass' : 'Fail'; self::logRequirementFail($dup_tests['SRV']['MYSQL_VER'], 'MySQL version '.$db_version.' is lower than 5.0.'); $dup_tests['SRV']['ALL'] = !in_array('Fail', $dup_tests['SRV']) ? 'Pass' : 'Fail'; //RESERVED FILES $dup_tests['RES']['INSTALL'] = !(self::hasInstallerFiles()) ? 'Pass' : 'Fail'; self::logRequirementFail($dup_tests['RES']['INSTALL'], 'Installer file(s) are exist on the server.'); $dup_tests['Success'] = $dup_tests['PHP']['ALL'] == 'Pass' && $dup_tests['IO']['ALL'] == 'Pass' && $dup_tests['SRV']['ALL'] == 'Pass' && $dup_tests['RES']['INSTALL'] == 'Pass'; $dup_tests['Warning'] = $dup_tests['IO']['WPROOT'] == 'Warn'; return $dup_tests; } /** * Logs requirement fail status informative message * * @param string $testStatus Either it is Pass or Fail * @param string $errorMessage Error message which should be logged * @return void */ private static function logRequirementFail($testStatus, $errorMessage) { if (empty($testStatus)) { throw new Exception('Exception: Empty $testStatus [File: '.__FILE__.', Ln: '.__LINE__); } if (empty($errorMessage)) { throw new Exception('Exception: Empty $errorMessage [File: '.__FILE__.', Ln: '.__LINE__); } $validTestStatuses = array('Pass', 'Fail', 'Warn'); if (!in_array($testStatus, $validTestStatuses)) { throw new Exception('Exception: Invalid $testStatus value: '.$testStatus.' [File: '.__FILE__.', Ln: '.__LINE__); } if ('Fail' == $testStatus) { DUP_LOG::trace($errorMessage); } } /** * Gets the system checks which are not required * * @return array An array of system checks */ public static function getChecks() { $checks = array(); //PHP/SYSTEM SETTINGS //Web Server $php_test0 = false; foreach ($GLOBALS['DUPLICATOR_SERVER_LIST'] as $value) { if (stristr($_SERVER['SERVER_SOFTWARE'], $value)) { $php_test0 = true; break; } } self::logCheckFalse($php_test0, 'Any out of server software ('.implode(', ', $GLOBALS['DUPLICATOR_SERVER_LIST']).') doesn\'t exist.'); $php_test1 = ini_get("open_basedir"); $php_test1 = empty($php_test1) ? true : false; self::logCheckFalse($php_test1, 'open_basedir is enabled.'); $max_execution_time = ini_get("max_execution_time"); $php_test2 = ($max_execution_time > DUPLICATOR_SCAN_TIMEOUT) || (strcmp($max_execution_time, 'Off') == 0 || $max_execution_time == 0) ? true : false; if (strcmp($max_execution_time, 'Off') == 0) { $max_execution_time_error_message = '$max_execution_time should not be'.$max_execution_time; } else { $max_execution_time_error_message = '$max_execution_time ('.$max_execution_time.') should not be lower than the DUPLICATOR_SCAN_TIMEOUT'.DUPLICATOR_SCAN_TIMEOUT; } self::logCheckFalse($php_test2, $max_execution_time_error_message); $php_test3 = function_exists('mysqli_connect'); self::logCheckFalse($php_test3, 'mysqli_connect function doesn\'t exist.'); $php_test4 = DUP_Util::$on_php_53_plus ? true : false; self::logCheckFalse($php_test4, 'PHP Version is lower than 5.3.'); $checks['SRV']['PHP']['websrv'] = $php_test0; $checks['SRV']['PHP']['openbase'] = $php_test1; $checks['SRV']['PHP']['maxtime'] = $php_test2; $checks['SRV']['PHP']['mysqli'] = $php_test3; $checks['SRV']['PHP']['version'] = $php_test4; //MANAGED HOST $checks['SRV']['SYS']['managedHost'] = !DUP_Custom_Host_Manager::getInstance()->isManaged(); $checks['SRV']['SYS']['ALL'] = ($php_test0 && $php_test1 && $php_test2 && $php_test3 && $php_test4 && $checks['SRV']['SYS']['managedHost']) ? 'Good' : 'Warn'; //WORDPRESS SETTINGS global $wp_version; $wp_test1 = version_compare($wp_version, DUPLICATOR_SCAN_MIN_WP) >= 0 ? true : false; self::logCheckFalse($wp_test1, 'WP version ('.$wp_version.') is lower than the DUPLICATOR_SCAN_MIN_WP ('.DUPLICATOR_SCAN_MIN_WP.').'); //Core Files $files = array(); $proper_wp_config_file_path = duplicator_get_abs_path().'/wp-config.php'; $files['wp-config.php'] = file_exists($proper_wp_config_file_path); self::logCheckFalse($files['wp-config.php'], 'The wp-config.php file doesn\'t exist on the '.$proper_wp_config_file_path); /** searching wp-config in working word press is not worthy * if this script is executing that means wp-config.php exists :) * we need to know the core folders and files added by the user at this point * retaining old logic as else for the case if its used some where else */ //Core dir and files logic if (isset($_POST['file_notice']) && isset($_POST['dir_notice'])) { //means if there are core directories excluded or core files excluded return false if ((bool) $_POST['file_notice'] || (bool) $_POST['dir_notice']) $wp_test2 = false; else $wp_test2 = true; } else { $wp_test2 = $files['wp-config.php']; } //Cache /* $Package = DUP_Package::getActive(); $cache_path = DUP_Util::safePath(WP_CONTENT_DIR) . '/cache'; $dirEmpty = DUP_Util::isDirectoryEmpty($cache_path); $dirSize = DUP_Util::getDirectorySize($cache_path); $cach_filtered = in_array($cache_path, explode(';', $Package->Archive->FilterDirs)); $wp_test3 = ($cach_filtered || $dirEmpty || $dirSize < DUPLICATOR_SCAN_CACHESIZE ) ? true : false; */ $wp_test3 = is_multisite(); self::logCheckFalse($wp_test3, 'WP is multi-site setup.'); $checks['SRV']['WP']['version'] = $wp_test1; $checks['SRV']['WP']['core'] = $wp_test2; $checks['SRV']['WP']['ismu'] = $wp_test3; $checks['SRV']['WP']['ALL'] = $wp_test1 && $wp_test2 && !$wp_test3 ? 'Good' : 'Warn'; return $checks; } /** * Logs checks false informative message * * @param boolean $check Either it is true or false * @param string $errorMessage Error message which should be logged when check is false * @return void */ private static function logCheckFalse($check, $errorMessage) { if (empty($errorMessage)) { throw new Exception('Exception: Empty $errorMessage variable [File: '.__FILE__.', Ln: '.__LINE__); } if (filter_var($check, FILTER_VALIDATE_BOOLEAN) === false) { DUP_LOG::trace($errorMessage); } } /** * Check to see if duplicator installer files are present * * @return bool True if any reserved files are found */ public static function hasInstallerFiles() { $files = self::getInstallerFiles(); foreach ($files as $file => $path) { if (false !== strpos($path, '*')) { $glob_files = glob($path); if (!empty($glob_files)) { return true; } } elseif (file_exists($path)) return true; } return false; } /** * Gets a list of all the installer files by name and full path * * @remarks * FILES: installer.php, installer-backup.php, dup-installer-bootlog__[HASH].txt * DIRS: dup-installer * DEV FILES: wp-config.orig * Last set is for lazy developer cleanup files that a developer may have * accidently left around lets be proactive for the user just in case. * * @return array [file_name, file_path] */ public static function getInstallerFiles() { // alphanumeric 7 time, then -(dash), then 8 digits $abs_path = duplicator_get_abs_path(); $four_digit_glob_pattern = '[0-9][0-9][0-9][0-9]'; $retArr = array( basename(DUPLICATOR_INSTALLER_DIRECTORY).' '.esc_html__('(directory)', 'duplicator') => DUPLICATOR_INSTALLER_DIRECTORY, DUPLICATOR_INSTALL_PHP => $abs_path.'/'.DUPLICATOR_INSTALL_PHP, '[HASH]'.'_'.DUPLICATOR_INSTALL_PHP => $abs_path.'/*_*'.$four_digit_glob_pattern.'_'.DUPLICATOR_INSTALL_PHP, DUPLICATOR_INSTALL_BAK => $abs_path.'/'.DUPLICATOR_INSTALL_BAK, '[HASH]'.'_'.DUPLICATOR_INSTALL_BAK => $abs_path.'/*_*'.$four_digit_glob_pattern.'_'.DUPLICATOR_INSTALL_BAK, '[HASH]_archive.zip|daf' => $abs_path.'/*_*'.$four_digit_glob_pattern.'_archive.[zd][ia][pf]', 'dup-installer-bootlog__[HASH].txt' => $abs_path.'/dup-installer-bootlog__'.DUPLICATOR_INSTALLER_HASH_PATTERN.'.txt', ); if (DUPLICATOR_INSTALL_SITE_OVERWRITE_ON) { $retArr['dup-wp-config-arc__[HASH].txt'] = $abs_path.'/dup-wp-config-arc__'.DUPLICATOR_INSTALLER_HASH_PATTERN.'.txt'; } return $retArr; } /** * Get the IP of a client machine * * @return string IP of the client machine */ public static function getClientIP() { if (array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER)) { return $_SERVER["HTTP_X_FORWARDED_FOR"]; } else if (array_key_exists('REMOTE_ADDR', $_SERVER)) { return $_SERVER["REMOTE_ADDR"]; } else if (array_key_exists('HTTP_CLIENT_IP', $_SERVER)) { return $_SERVER["HTTP_CLIENT_IP"]; } return ''; } /** * Get PHP memory usage * * @return string Returns human readable memory usage. */ public static function getPHPMemory($peak = false) { if ($peak) { $result = 'Unable to read PHP peak memory usage'; if (function_exists('memory_get_peak_usage')) { $result = DUP_Util::byteSize(memory_get_peak_usage(true)); } } else { $result = 'Unable to read PHP memory usage'; if (function_exists('memory_get_usage')) { $result = DUP_Util::byteSize(memory_get_usage(true)); } } return $result; } }
| ver. 1.4 |
Github
|
.
| PHP 8.2.29 | Генерация страницы: 0 |
proxy
|
phpinfo
|
Настройка