
@magento_sample_tables = (
  "admin_analytics_usage_version_log",
  "admin_passwords",
  "admin_system_messages",
  "admin_user",
  "admin_user_expiration",
  "admin_user_session",
  "adminnotification_inbox",
  "adobe_stock_asset",
  "adobe_stock_category",
  "adobe_stock_creator",
  "adobe_user_profile",
  "amazon_customer",
  "amazon_pending_authorization",
  "amazon_pending_capture",
  "amazon_pending_refund",
  "amazon_quote",
  "amazon_sales_order",
  "authorization_role",
  "authorization_rule",
  "braintree_credit_prices",
  "braintree_transaction_details",
  "cache",
  "cache_tag",
  "captcha_log",
  "catalog_category_entity",
  "catalog_category_entity_datetime",
  "catalog_category_entity_decimal",
  "catalog_category_entity_int",
  "catalog_category_entity_text",
  "catalog_category_entity_varchar",
  "catalog_category_product",
  "catalog_category_product_index",
  "catalog_category_product_index_replica",
  "catalog_category_product_index_store1",
  "catalog_category_product_index_store1_replica",
  "catalog_category_product_index_tmp",
  "catalog_compare_item",
  "catalog_eav_attribute",
  "catalog_product_bundle_option",
  "catalog_product_bundle_option_value",
  "catalog_product_bundle_price_index",
  "catalog_product_bundle_selection",
  "catalog_product_bundle_selection_price",
  "catalog_product_bundle_stock_index",
  "catalog_product_entity",
  "catalog_product_entity_datetime",
  "catalog_product_entity_decimal",
  "catalog_product_entity_gallery",
  "catalog_product_entity_int",
  "catalog_product_entity_media_gallery",
  "catalog_product_entity_media_gallery_value",
  "catalog_product_entity_media_gallery_value_to_entity",
  "catalog_product_entity_media_gallery_value_video",
  "catalog_product_entity_text",
  "catalog_product_entity_tier_price",
  "catalog_product_entity_varchar",
  "catalog_product_frontend_action",
  "catalog_product_index_eav",
  "catalog_product_index_eav_decimal",
  "catalog_product_index_eav_decimal_idx",
  "catalog_product_index_eav_decimal_replica",
  "catalog_product_index_eav_decimal_tmp",
  "catalog_product_index_eav_idx",
  "catalog_product_index_eav_replica",
  "catalog_product_index_eav_tmp",
  "catalog_product_index_price",
  "catalog_product_index_price_bundle_idx",
  "catalog_product_index_price_bundle_opt_idx",
  "catalog_product_index_price_bundle_opt_tmp",
  "catalog_product_index_price_bundle_sel_idx",
  "catalog_product_index_price_bundle_sel_tmp",
  "catalog_product_index_price_bundle_tmp",
  "catalog_product_index_price_cfg_opt_agr_idx",
  "catalog_product_index_price_cfg_opt_agr_tmp",
  "catalog_product_index_price_cfg_opt_idx",
  "catalog_product_index_price_cfg_opt_tmp",
  "catalog_product_index_price_downlod_idx",
  "catalog_product_index_price_downlod_tmp",
  "catalog_product_index_price_final_idx",
  "catalog_product_index_price_final_tmp",
  "catalog_product_index_price_idx",
  "catalog_product_index_price_opt_agr_idx",
  "catalog_product_index_price_opt_agr_tmp",
  "catalog_product_index_price_opt_idx",
  "catalog_product_index_price_opt_tmp",
  "catalog_product_index_price_replica",
  "catalog_product_index_price_tmp",
  "catalog_product_index_tier_price",
  "catalog_product_index_website",
  "catalog_product_link",
  "catalog_product_link_attribute",
  "catalog_product_link_attribute_decimal",
  "catalog_product_link_attribute_int",
  "catalog_product_link_attribute_varchar",
  "catalog_product_link_type",
  "catalog_product_option",
  "catalog_product_option_price",
  "catalog_product_option_title",
  "catalog_product_option_type_price",
  "catalog_product_option_type_title",
  "catalog_product_option_type_value",
  "catalog_product_relation",
  "catalog_product_super_attribute",
  "catalog_product_super_attribute_label",
  "catalog_product_super_link",
  "catalog_product_website",
  "catalog_url_rewrite_product_category",
  "cataloginventory_stock",
  "cataloginventory_stock_item",
  "cataloginventory_stock_status",
  "cataloginventory_stock_status_idx",
  "cataloginventory_stock_status_replica",
  "cataloginventory_stock_status_tmp",
  "catalogrule",
  "catalogrule_customer_group",
  "catalogrule_group_website",
  "catalogrule_group_website_replica",
  "catalogrule_product",
  "catalogrule_product_price",
  "catalogrule_product_price_replica",
  "catalogrule_product_replica",
  "catalogrule_website",
  "catalogsearch_recommendations",
  "checkout_agreement",
  "checkout_agreement_store",
  "cms_block",
  "cms_block_store",
  "cms_page",
  "cms_page_store",
  "core_config_data",
  "cron_schedule",
  "customer_address_entity",
  "customer_address_entity_datetime",
  "customer_address_entity_decimal",
  "customer_address_entity_int",
  "customer_address_entity_text",
  "customer_address_entity_varchar",
  "customer_eav_attribute",
  "customer_eav_attribute_website",
  "customer_grid_flat",
  "customer_entity",
  "customer_entity_datetime",
  "customer_entity_decimal",
  "customer_entity_int",
  "customer_entity_text",
  "customer_entity_varchar",
  "customer_form_attribute",
  "customer_group",
  "customer_log",
  "customer_visitor",
  "design_change",
  "design_config_grid_flat",
  "directory_country",
  "directory_country_format",
  "directory_country_region",
  "directory_country_region_name",
  "directory_currency_rate",
  "downloadable_link",
  "downloadable_link_price",
  "downloadable_link_purchased",
  "downloadable_link_purchased_item",
  "downloadable_link_title",
  "downloadable_sample",
  "downloadable_sample_title",
  "eav_attribute",
  "eav_attribute_group",
  "eav_attribute_label",
  "eav_attribute_option",
  "eav_attribute_option_swatch",
  "eav_attribute_option_value",
  "eav_attribute_set",
  "eav_entity",
  "eav_entity_attribute",
  "eav_entity_datetime",
  "eav_entity_decimal",
  "eav_entity_int",
  "eav_entity_store",
  "eav_entity_text",
  "eav_entity_type",
  "eav_entity_varchar",
  "eav_form_element",
  "eav_form_fieldset",
  "eav_form_fieldset_label",
  "eav_form_type",
  "eav_form_type_entity",
  "email_abandoned_cart",
  "email_automation",
  "email_campaign",
  "email_catalog",
  "email_contact",
  "email_contact_consent",
  "email_coupon_attribute",
  "email_failed_auth",
  "email_importer",
  "email_order",
  "email_review",
  "email_rules",
  "email_template",
  "email_wishlist",
  "flag",
  "gift_message",
  "googleoptimizer_code",
  "import_history",
  "importexport_importdata",
  "indexer_state",
  "integration",
  "inventory_geoname",
  "inventory_low_stock_notification_configuration",
  "inventory_order_notification",
  "inventory_pickup_location_order",
  "inventory_pickup_location_quote_address",
  "inventory_reservation",
  "inventory_shipment_source",
  "inventory_source",
  "inventory_source_carrier_link",
  "inventory_source_item",
  "inventory_source_stock_link",
  "inventory_stock",
  "inventory_stock_sales_channel",
  "klarna_core_order",
  "klarna_payments_quote",
  "layout_link",
  "layout_update",
  "login_as_customer",
  "login_as_customer_assistance_allowed",
  "magento_acknowledged_bulk",
  "magento_bulk",
  "magento_login_as_customer_log",
  "magento_operation",
  "media_content_asset",
  "media_gallery_asset",
  "media_gallery_asset_keyword",
  "media_gallery_keyword",
  "mview_state",
  "newsletter_problem",
  "newsletter_queue",
  "newsletter_queue_link",
  "newsletter_queue_store_link",
  "newsletter_subscriber",
  "newsletter_template",
  "oauth_consumer",
  "oauth_nonce",
  "oauth_token",
  "oauth_token_request_log",
  "password_reset_request_event",
  "patch_list",
  "paypal_billing_agreement",
  "paypal_billing_agreement_order",
  "paypal_cert",
  "paypal_payment_transaction",
  "paypal_settlement_report",
  "paypal_settlement_report_row",
  "persistent_session",
  "product_alert_price",
  "product_alert_stock",
  "queue",
  "queue_lock",
  "queue_message",
  "queue_message_status",
  "queue_poison_pill",
  "quote",
  "quote_address",
  "quote_address_item",
  "quote_id_mask",
  "quote_item",
  "quote_item_option",
  "quote_payment",
  "quote_shipping_rate",
  "rating",
  "rating_entity",
  "rating_option",
  "rating_option_vote",
  "rating_option_vote_aggregated",
  "rating_store",
  "rating_title",
  "release_notification_viewer_log",
  "report_compared_product_index",
  "report_event",
  "report_event_types",
  "report_viewed_product_aggregated_daily",
  "report_viewed_product_aggregated_monthly",
  "report_viewed_product_aggregated_yearly",
  "report_viewed_product_index",
  "reporting_counts",
  "reporting_module_status",
  "reporting_orders",
  "reporting_system_updates",
  "reporting_users",
  "review",
  "review_detail",
  "review_entity",
  "review_entity_summary",
  "review_status",
  "review_store",
  "sales_bestsellers_aggregated_daily",
  "sales_bestsellers_aggregated_monthly",
  "sales_bestsellers_aggregated_yearly",
  "sales_creditmemo",
  "sales_creditmemo_comment",
  "sales_creditmemo_grid",
  "sales_creditmemo_item",
  "sales_invoice",
  "sales_invoice_comment",
  "sales_invoice_grid",
  "sales_invoice_item",
  "sales_invoiced_aggregated",
  "sales_invoiced_aggregated_order",
  "sales_order",
  "sales_order_address",
  "sales_order_aggregated_created",
  "sales_order_aggregated_updated",
  "sales_order_grid",
  "sales_order_item",
  "sales_order_payment",
  "sales_order_status",
  "sales_order_status_history",
  "sales_order_status_label",
  "sales_order_status_state",
  "sales_order_tax",
  "sales_order_tax_item",
  "sales_payment_transaction",
  "sales_refunded_aggregated",
  "sales_refunded_aggregated_order",
  "sales_sequence_meta",
  "sales_sequence_profile",
  "sales_shipment",
  "sales_shipment_comment",
  "sales_shipment_grid",
  "sales_shipment_item",
  "sales_shipment_track",
  "sales_shipping_aggregated",
  "sales_shipping_aggregated_order",
  "salesrule",
  "salesrule_coupon",
  "salesrule_coupon_aggregated",
  "salesrule_coupon_aggregated_order",
  "salesrule_coupon_aggregated_updated",
  "salesrule_coupon_usage",
  "salesrule_customer",
  "salesrule_customer_group",
  "salesrule_label",
  "salesrule_product_attribute",
  "salesrule_website",
  "search_query",
  "search_synonyms",
  "sendfriend_log",
  "sequence_creditmemo_0",
  "sequence_creditmemo_1",
  "sequence_invoice_0",
  "sequence_invoice_1",
  "sequence_order_0",
  "sequence_order_1",
  "sequence_shipment_0",
  "sequence_shipment_1",
  "session",
  "setup_module",
  "shipping_tablerate",
  "sitemap",
  "store",
  "store_group",
  "store_website",
  "tax_calculation",
  "tax_calculation_rate",
  "tax_calculation_rate_title",
  "tax_calculation_rule",
  "tax_class",
  "tax_order_aggregated_created",
  "tax_order_aggregated_updated",
  "tfa_country_codes",
  "tfa_user_config",
  "theme",
  "theme_file",
  "translation",
  "ui_bookmark",
  "url_rewrite",
  "variable",
  "variable_value",
  "vault_payment_token",
  "vault_payment_token_order_payment_link",
  "vertex_custom_option_flex_field",
  "vertex_customer_code",
  "vertex_customer_country",
  "vertex_invoice_sent",
  "vertex_order_invoice_status",
  "vertex_sales_creditmemo_item_invoice_text_code",
  "vertex_sales_creditmemo_item_tax_code",
  "vertex_sales_creditmemo_item_vertex_tax_code",
  "vertex_sales_order_item_invoice_text_code",
  "vertex_sales_order_item_tax_code",
  "vertex_sales_order_item_vertex_tax_code",
  "vertex_taxrequest",
  "vertex_vat_country_code",
  "weee_tax",
  "widget",
  "widget_instance",
  "widget_instance_page",
  "widget_instance_page_layout",
  "wishlist",
  "wishlist_item",
  "wishlist_item_option",
  "yotpo_order_status_history",
  "yotpo_rich_snippets",
  "yotpo_sync" );

# script_magento_desc()
sub script_magento_desc
{
return "Magento";
}

sub script_magento_uses
{
return ( "php" );
}

sub script_magento_longdesc
{
return "Magento is a new professional open-source eCommerce solution offering unprecedented flexibility and control";
}

# script_magento_versions()
sub script_magento_versions
{
# Note - new versions must be manually downloaded and uploaded to
# scripts.virtualmin.com/
return ( "2.4.4", "2.3.7", "2.2.11" );
}

sub script_magento_release
{
return 8;	# To roll back version 2.4.5
}

sub script_magento_can_upgrade
{
local ($sinfo, $newver) = @_;
if ($newver >= 1.6 && $sinfo->{'version'} < 1.6) {
	# Cannot upgrade 1.5 to 1.6
	return 0;
	}
return 1;
}

sub script_magento_category
{
return "Commerce";
}

sub script_magento_php_vars
{
return ( [ 'memory_limit', '2G', '+' ],
         [ 'realpath_cache_size', '16M', '+' ],
         [ 'realpath_cache_ttl', '7200', '+' ] );
}


sub script_magento_php_vers
{
return ( 5 );
}

sub script_magento_php_modules
{
return ( "mysql", "xml", "curl", "intl", "gd", 
         "zip", "bcmath", "ctype", "dom", 
         "iconv", "mbstring", "sockets" );
}

sub script_magento_php_optional_modules
{
return ( "pdo_mysql", "soap", "hash", "openssl", "sodium" );
}

sub script_magento_dbs
{
return ("mysql");
}

# script_magento_depends(&domain, version)
sub script_magento_depends
{
local ($d, $ver, $sinfo, $phpver) = @_;
local @rv;

# Check for MySQL 4.1.20+
if (defined(&get_dom_remote_mysql_version)) {
	my ($myver, $variant) = &get_dom_remote_mysql_version($d);
	local $wantver = $ver >= 2.2 ? "5.6.0" : "4.1.20";
	if (&compare_versions($myver, $wantver) < 0) {
		push(@rv, "Magento requires MySQL version $wantver or later");
		}
	}

return @rv;
}

sub script_magento_php_fullver
{
local ($d, $ver, $sinfo) = @_;
return &compare_versions($ver, "2.3.6") > 0 ? "7.4" :
       &compare_versions($ver, "2.2") < 0 ? "7.0" : "7.2";
}

# script_magento_params(&domain, version, &upgrade-info)
# Returns HTML for table rows for options for installing Magento
sub script_magento_params
{
local ($d, $ver, $upgrade) = @_;
local $rv;
local $hdir = &public_html_dir($d, 1);
if ($upgrade) {
	# Options are fixed when upgrading
	local ($dbtype, $dbname) = split(/_/, $upgrade->{'opts'}->{'db'}, 2);
	$rv .= &ui_table_row("Database for Magento tables", $dbname);
	local $dir = $upgrade->{'opts'}->{'dir'};
	$dir =~ s/^$d->{'home'}\///;
	$rv .= &ui_table_row("Install directory", $dir);
	}
else {
	# Show editable install options
	local @dbs = &domain_databases($d, [ "mysql" ]);
	$rv .= &ui_table_row("Database for Magento tables",
		     &ui_database_select("db", undef, \@dbs, $d, "magento"));
	$rv .= &ui_table_row("Install sub-directory under <tt>$hdir</tt>",
			     &ui_opt_textbox("dir", &substitute_scriptname_template("magento", $d), 30, "At top level"));
	if ($ver < 2) {
		$rv .= &ui_table_row("Install sample data?",
				     &ui_yesno_radio("sample", 0));
		}
	}
return $rv;
}

# script_magento_parse(&domain, version, &in, &upgrade-info)
# Returns either a hash ref of parsed options, or an error string
sub script_magento_parse
{
local ($d, $ver, $in, $upgrade) = @_;
if ($upgrade) {
	# Options are always the same
	return $upgrade->{'opts'};
	}
else {
	local $hdir = &public_html_dir($d, 0);
	$in{'dir_def'} || $in{'dir'} =~ /\S/ && $in{'dir'} !~ /\.\./ ||
		return "Missing or invalid installation directory";
	local $dir = $in{'dir_def'} ? $hdir : "$hdir/$in{'dir'}";
	local ($newdb) = ($in->{'db'} =~ s/^\*//);
	return { 'db' => $in->{'db'},
		 'newdb' => $newdb,
	         'dir' => $dir,
		 'sample' => $in->{'sample'},
		 'path' => $in{'dir_def'} ? "/" : "/$in{'dir'}", };
	}
}

# script_magento_check(&domain, version, &opts, &upgrade-info)
# Returns an error message if a required option is missing or invalid
sub script_magento_check
{
local ($d, $ver, $opts, $upgrade) = @_;
$opts->{'dir'} =~ /^\// || return "Missing or invalid install directory";
$opts->{'db'} || return "Missing database";
if (-r "$opts->{'dir'}/index.php") {
	return "Magento appears to be already installed in the selected directory";
	}
local ($dbtype, $dbname) = split(/_/, $opts->{'db'}, 2);
local $clash = &find_database_table($dbtype, $dbname, "magento_");
$clash && return "Magento appears to be already using the selected database (table $clash)";
return undef;
}

# script_magento_files(&domain, version, &opts, &upgrade-info)
# Returns a list of files needed by Magento, each of which is a hash ref
# containing a name, filename and URL
sub script_magento_files
{
local ($d, $ver, $opts, $upgrade) = @_;
local @files = ( { 'name' => "source",
	   'file' => "magento-$ver.tar.gz",
	   'virtualmin' => 1,
	   'url' => "http://scripts.virtualmin.com/magento-$ver.tar.gz" });
if ($opts->{'sample'} && !$upgrade) {
	my $sver = $ver;
	$sver =~ s/^(\d+\.\d+).*/$1/;
	push(@files, { 'name' => 'sample',
		       'file' => "magento-sample-data-$sver.tar.gz",
	   	       'virtualmin' => 1,
		       'url' => "http://scripts.virtualmin.com/magento-sample-data-$sver.tar.gz",
		     });
	}
return @files;
}

sub script_magento_commands
{
return ("unzip");
}

# script_magento_install(&domain, version, &opts, &files, &upgrade-info)
# Actually installs Magento, and returns either 1 and an informational
# message, or 0 and an error
sub script_magento_install
{
local ($d, $version, $opts, $files, $upgrade, $domuser, $dompass) = @_;
local ($out, $ex);

if ($opts->{'newdb'} && !$upgrade) {
	local $err = &create_script_database($d, $opts->{'db'});
	return (0, "Database creation failed : $err") if ($err);
	}
local ($dbtype, $dbname) = split(/_/, $opts->{'db'}, 2);
local $dbuser = &mysql_user($d);
local $dbpass = &mysql_pass($d);
local $dbhost = &get_database_host($dbtype, $d);
local $dberr = &check_script_db_connection($dbtype, $dbname, $dbuser, $dbpass);
return (0, "Database connection failed : $dberr") if ($dberr);

# Extract tar file to temp dir and copy to target
local $temp = &transname();
local $err = &extract_script_archive($files->{'source'}, $temp, $d,
		$opts->{'dir'},
		&compare_versions($ver, 2) >= 0 ? undef : "magento");
$err && return (0, "Failed to extract source : $err");

# Extract sample data and copy to target
local $sampletemp = &transname();
if ($opts->{'sample'} && !$upgrade) {
	local $err = &extract_script_archive($files->{'sample'}, $sampletemp,
			     $d, $opts->{'dir'}, "magento-sample-data-*");
	$err && return (0, "Failed to extract sample data : $err");
	}

# Run sample SQL
if ($opts->{'sample'} && !$upgrade) {
	local ($sqlfile) = glob("$opts->{'dir'}/magento_sample_data_for_*.sql");
	$sqlfile || return (-1, "Could not find sample data SQL file at $opts->{'dir'}/magento_sample_data_for_*.sql");
	my ($ex, $out) = &mysql::execute_sql_file(
				$dbname, $sqlfile, $dbuser, $dbpass);
	$ex && return (-1, "Failed to run sample data SQL : <tt>$out</tt>");
	}

# Make needed directories writable
&make_file_php_writable($d, "$opts->{'dir'}/var/.htaccess");
&make_file_php_writable($d, "$opts->{'dir'}/app/etc", 1);
&make_file_php_writable($d, "$opts->{'dir'}/var", 1);
&make_file_php_writable($d, "$opts->{'dir'}/media");

local $url = &script_path_url($d, $opts);
local $longpass = $dompass;

if (!$upgrade) {
	# Build the command line to call Magento's install script
	local $cmd = &get_php_cli_command($opts->{'phpver'});
	if (length($longpass) < 6 || $longpass !~ /[0-9]/) {
		$longpass .= "123456";
		}
	local ($firstname, $lastname) = split(/\s+/, $d->{'owner'});
	$opts->{'enckey'} = &random_password(16);
	local $securl = $url;
	$securl =~ s/^http:/https:/;
	if ($ver >= 2) {
		# New command syntax
		$cmd .= " -f ".$opts->{'dir'}."/bin/magento setup:install";
		$cmd .= " --base-url=".quotemeta($url);
		$cmd .= " --db-host=".quotemeta($dbhost);
		$cmd .= " --db-name=".quotemeta($dbname);
		$cmd .= " --db-user=".quotemeta($dbuser);
		$cmd .= " --db-password=".quotemeta($dbpass);
		$cmd .= " --admin-firstname=".quotemeta($firstname || "none");
		$cmd .= " --admin-lastname=".quotemeta($lastname || "none");
		$cmd .= " --admin-email=".quotemeta($d->{'emailto_addr'});
		$cmd .= " --admin-user=".quotemeta($domuser);
		$cmd .= " --admin-password=".quotemeta($longpass);
		$cmd .= " --language=en_US";
		$cmd .= " --currency=USD";
		$cmd .= " --timezone=Europe/London";
        if ($ver >= 2.4) {
            # Yet, only partial install, unless Elastisearch service is pre-installed
            $cmd .= " --search-engine=elasticsearch7";
            $cmd .= " --elasticsearch-host=127.0.0.1";
            $cmd .= " --elasticsearch-port=9200";
            $cmd .= " --elasticsearch-enable-auth=0";
            }
		}
	local $p = &domain_has_website($d);
	if ($p eq 'web') {
		&require_apache();
		if ($apache::httpd_modules{'mod_rewrite'}) {
			if ($ver >= 2) {
				$cmd .= " --use-rewrites=1";
				}
			else {
				$cmd .= " --use_rewrites yes";
				}
			}
		}
	local $phpver = $opts->{'phpver'} || 5;
	if (-d "$d->{'home'}/etc/php$phpver") {
		$cmd = "PHPRC=$d->{'home'}/etc/php$phpver $cmd";
		}

	# Run it as the domain owner
	local $out = &run_as_domain_user($d,
		"cd ".quotemeta($opts->{'dir'})." && ".$cmd." 2>&1");
	if ($? || $out =~ /FAILED/) {
        my $os_type = $gconfig{'os_type'} eq 'redhat-linux' ? 'rpm' : 'deb';
        my $msg_24 = $ver >= 2.4 ? "<br><b>@{[&ui_text_color('Note:', 'danger', 1)]}</b> For Magento $ver <a target='_blank' href='https://www.elastic.co/guide/en/elasticsearch/reference/current/$os_type.html'>Elasticsearch</a> must be pre-installed and running before this installation can be accomplished.<br><br>" : "";
		return (-1, "Installation script failed : <pre>".
			    &html_escape($out)."</pre>$msg_24");
		}
	}
else {
	# Clear out the cache and session directories, as these objects are
	# not valid for new versions
	&run_as_domain_user($d,
		"rm -rf ".quotemeta("$opts->{'dir'}/var/cache")."/*");
	&run_as_domain_user($d,
		"rm -rf ".quotemeta("$opts->{'dir'}/var/session")."/*");
	}

# Check for a random admin URL
local $admin = "admin";
local $efile = "$opts->{'dir'}/app/etc/env.php";
if (-r $efile) {
	my $lref = &read_file_lines($efile, 1);
	foreach my $l (@$lref) {
		if ($l =~ /'frontName'\s+=>\s+'(.*)'/) {
			$admin = $1;
			}
		}
	}

# Tell the user about the new install
local $rp = $opts->{'dir'};
$rp =~ s/^$d->{'home'}\///;
local $adminurl = $url."index.php/$admin/";
return (1, "Initial Magento installation complete. Go to <a target=_blank href='$adminurl'>$adminurl</a> to manage it.", "Under $rp using MySQL database $dbname", $url, $domuser, $longpass );
}

# script_magento_uninstall(&domain, version, &opts)
# Un-installs a Magento installation, by removing it's files
# Returns 1 on success and a message, or 0 on failure and an error
sub script_magento_uninstall
{
local ($d, $version, $opts) = @_;

# Remove magento tables from the database
local $tries = 0;
while(1) {
	local $err = &cleanup_script_database($d, $opts->{'db'}, \@magento_sample_tables);
	last if (!$err || $err =~ /Unknown\s+database/i);
	if ($tries++ > 1000) {
		return (0, "Failed to delete all Magento tables ".
			   "after 1000 attempts : $err");
		}
	}

# Remove the contents of the target directory
local $derr = &delete_script_install_directory($d, $opts);
return (0, $derr) if ($derr);

# Take out the DB
if ($opts->{'newdb'}) {
	&delete_script_database($d, $opts->{'db'});
	}

return (1, "Deleted Magento directory and tables.");
}

# script_magento_latest(version)
# Returns a URL and regular expression or callback func to get the version
sub script_magento_latest
{
local ($ver) = @_;
return ( "https://experienceleague.adobe.com/docs/commerce-operations/release/versions.html", 
	 $ver >= 2.4 ? ">(2\\.[0-9]\\.[0-9\\.]+)<" :
	 $ver >= 2.3 ? ">(2\\.3\\.[0-9\\.]+)<" :
	 $ver >= 2.2 ? ">(2\\.2\\.[0-9\\.]+)<" : undef );
}

sub script_magento_site
{
return 'http://www.magentocommerce.com/';
}

sub script_magento_passmode
{
return (1, 7, '^(?=.*[\p{L}])(?=.*\d)[\p{L}\d]{7,}$');
}

1;

