Created
June 25, 2020 22:00
-
-
Save dfelton/c5d15dccb8ab62a878ae04c2da9ee207 to your computer and use it in GitHub Desktop.
Generates sample data in Magento by via cURL requests to the Magento admin. Useful if CLI access and access to System -> Import/Export is restricted.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class Config | |
{ | |
public static $adminUsername = ''; | |
public static $adminPassword = ''; | |
public static $expectedLoginLandingRoute = '/index/index/'; | |
public static $authCookieName = 'adminhtml'; | |
public static $authCookie = ''; // (leave blank if you've filled out username and password) | |
public static $magentoRootUrl = 'https://www.example.com'; // (no trailing slash after TLD) | |
public static $adminFrontName = 'admin'; // (as configured in app/etc/local.xml) | |
public static $attributeSetId = 4; | |
public static $typeId = 'simple'; | |
public static $productsToCreate = 500; | |
public static $skuPrefix = ''; // can leave blank if desired, will generate md5 hash of time() if so | |
public static $baseData = [ | |
'name' => null, // leave null to have match SKU (otherwise will be same for every product) | |
'description' => 'description', | |
'short_description' => 'short description', | |
'weight' => 0, | |
'status' => 2, | |
'visibility' => 4, | |
'price' => 10, | |
'msrp_enabled' => 2, | |
'msrp_display_actual_price_type' => 4, | |
'tax_class_id' => 0, | |
'is_recurring' => 0, | |
'options_container' => 'container1', | |
'use_config_gift_message_available' => 1, | |
'website_ids' => [ | |
1, | |
], | |
'stock_data' => [ | |
'use_config_manage_stock' => 1, | |
'original_inventory_qty' => 0, | |
'qty' => 0, | |
'use_config_min_qty' => 1, | |
'use_config_min_sale_qty' => 1, | |
'use_config_max_sale_qty' => 1, | |
'is_qty_decimal' => 0, | |
'is_decimal_divided' => 0, | |
'use_config_backorders' => 1, | |
'use_config_notify_stock_qty' => 1, | |
'use_config_enable_qty_increments' => 1, | |
'use_config_qty_increments' => 1, | |
'is_in_stock' => 0, | |
] | |
]; | |
} | |
class Tools | |
{ | |
public static function getHandle(string $url, $key = null) | |
{ | |
if (strpos($url, 'https://') !== 0) { | |
$url = Config::$magentoRootUrl . '/index.php/' . Config::$adminFrontName . '/' . $url . '/'; | |
if ($key) { | |
$url .= "key/$key/"; | |
} | |
} | |
$ch = curl_init($url); | |
if (Config::$authCookie) { | |
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Cookie: ' . Config::$authCookieName . '=' . Config::$authCookie]); | |
} | |
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); | |
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); | |
curl_setopt($ch, CURLOPT_HEADER, 1); | |
curl_setopt($ch, CURLINFO_HEADER_OUT, true); | |
return $ch; | |
} | |
public static function getResponseAndClose($ch): string | |
{ | |
$response = curl_exec($ch); | |
$errno = curl_errno($ch); | |
if ($errno !== 0) { | |
echo 'cURL Error: ' . $errno . "\n"; | |
echo 'cURL Error Message: ' . curl_error($ch) . "\n"; | |
$info = curl_getinfo($ch); | |
if ($info['request_header'] ?? false) { | |
echo "Request Headers:\n"; | |
foreach (explode("\n", $info['request_header']) as $header) { | |
echo "\t$header\n"; | |
} | |
} | |
echo "\n"; | |
curl_close($ch); | |
exit(1); | |
} | |
curl_close($ch); | |
return $response; | |
} | |
public static function findAnchorHrefWithString(string $haystack, string $needle): ?string | |
{ | |
$regexp = "<a\s[^>]*href=(\"??)([^\" >]*?)\\1[^>]*>(.*)<\/a>"; | |
if (preg_match_all("/$regexp/siU", $haystack, $matches, PREG_SET_ORDER)) { | |
foreach($matches as $match) { | |
if (($match[2] ?? false) && strpos($match[2], $needle) !== false) { | |
return $match[2]; | |
} | |
} | |
} | |
return null; | |
} | |
public static function findButtonKey(string $haystack, string $needle): ?string | |
{ | |
if (preg_match("@$needle/key/([^\"']+)@", $haystack, $matches)) { | |
return str_replace('/', '', $matches[1]); | |
} | |
return null; | |
} | |
public static function findFormAction(string $haystack, string $needle): ?string | |
{ | |
$regexp = "<form\s[^>]*action=(\"??)([^\" >]*?)\\1[^>]*>(.*)<\/form>"; | |
if (preg_match_all("/$regexp/siU", $haystack, $matches, PREG_SET_ORDER)) { | |
foreach($matches as $match) { | |
if (($match[2] ?? false) && strpos($match[2], $needle) !== false) { | |
return $match[2]; | |
} | |
} | |
} | |
return null; | |
} | |
/** | |
* Finds the current form_key (will not work if page is minified) | |
* | |
* @param string $haystack | |
* @return string|null | |
*/ | |
public static function findFormKey(string $haystack): ?string | |
{ | |
foreach (explode("\n", $haystack) as $line) { | |
if (strpos($line, 'var FORM_KEY = ') !== false) { | |
return trim(str_replace("';", '', substr($line, strpos($line, "'")+1))); | |
} | |
} | |
return null; | |
} | |
public static function getSaveProductKeyAndFormAction(string $keyForAddProduct = null): array | |
{ | |
if ($keyForAddProduct === null) { | |
// request the dashboard and start navigating to add product page. | |
$dashboard = Tools::getResponseAndClose(Tools::getHandle('dashboard/index')); | |
$linkToProductGrid = Tools::findAnchorHrefWithString( | |
$dashboard, | |
'/catalog_product/index/key/' | |
); | |
if ($linkToProductGrid === null) { | |
echo $dashboard, "\n"; | |
echo "ERROR: Link to product grid not found\n"; | |
exit(1); | |
} | |
// Navigate to add product page | |
$keyForAddProduct = Tools::findButtonKey( | |
Tools::getResponseAndClose(Tools::getHandle($linkToProductGrid)), | |
'\/catalog_product\/new' | |
); | |
if ($keyForAddProduct === null) { | |
echo "ERROR: Key for navigating to add product page not found\n"; | |
exit(1); | |
} | |
} | |
$editProductPage = Tools::getResponseAndClose( | |
Tools::getHandle( | |
'catalog_product/new/set/' . Config::$attributeSetId . '/type/' . Config::$typeId, | |
$keyForAddProduct | |
) | |
); | |
$formKey = Tools::findFormKey($editProductPage); | |
if ($formKey === null) { | |
echo "ERROR: Form key for edit product not found\n"; | |
exit(1); | |
} | |
$formAction = Tools::findFormAction($editProductPage, 'catalog_product/save'); | |
if ($formAction === null) { | |
echo "ERROR: Form action for saving product from edit product page not found\n"; | |
exit; | |
} | |
return [ | |
'key' => $formKey, | |
'action' => $formAction, | |
]; | |
} | |
public static function getSaveProductPostData(string $formKey, int $iteration = null): array | |
{ | |
$data = [ | |
'form_key' => $formKey, | |
'product' => Config::$baseData, | |
]; | |
$data['product']['sku'] = Config::$skuPrefix . ($iteration === null ? '' : '_' . $iteration); | |
if (!($data['product']['name'] ?? false)) { | |
$data['product']['name'] = $data['product']['sku']; | |
} | |
return $data; | |
} | |
public static function setAuthCookie(string $response) | |
{ | |
$authCoookieSet = false; | |
$timesSet = 0; | |
foreach (explode("\n", $response) as $line) { | |
if (strpos($line, 'set-cookie: ' . Config::$authCookieName . '=') === 0) { | |
$cookie = substr($line, strlen('set-cookie: ' . Config::$authCookieName . '=')); | |
$cookie = explode(';', $cookie); | |
$cookie = trim($cookie[0]); | |
if ($cookie === 'deleted' || $cookie === Config::$authCookie) { | |
continue; | |
} | |
$timesSet++; | |
Config::$authCookie = $cookie; | |
echo "Auth Cookie Set: $cookie\n"; | |
$authCoookieSet = true; | |
if ($timesSet == 2) { | |
break; | |
} | |
} | |
} | |
if (!$authCoookieSet) { | |
echo "ERROR: Auth cookie not set\n"; | |
exit(1); | |
} | |
} | |
public static function login(): bool | |
{ | |
$response = Tools::getResponseAndClose( | |
Tools::getHandle(Config::$magentoRootUrl . '/index.php/' . Config::$adminFrontName . '/') | |
); | |
$lines = explode("\n", $response); | |
$formKey = null; | |
Tools::setAuthCookie($response); | |
foreach ($lines as $line) { | |
if (strpos($line, 'form_key') !== false) { | |
$formKey = explode('"', $line); | |
$formKey = $formKey[5]; | |
} | |
} | |
if ($formKey === null) { | |
echo "Error: Form key not found."; | |
exit(1); | |
} | |
$ch = Tools::getHandle(Config::$magentoRootUrl . '/index.php/' . Config::$adminFrontName . '/'); | |
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); | |
curl_setopt($ch, CURLOPT_POST, 1); | |
curl_setopt( | |
$ch, | |
CURLOPT_POSTFIELDS, | |
http_build_query([ | |
'form_key' => $formKey, | |
'login' => [ | |
'username' => Config::$adminUsername, | |
'password' => Config::$adminPassword, | |
], | |
]) | |
); | |
$response = curl_exec($ch); | |
Tools::setAuthCookie($response); | |
foreach (explode("\n", $response) as $header) { | |
if (strpos($header, 'location: ') === 0) { | |
$location = explode(': ', $header); | |
$location = $location[1]; | |
if (strpos($location, Config::$expectedLoginLandingRoute) !== false) { | |
return true; | |
} | |
} | |
} | |
return false; | |
} | |
} | |
if (Config::$authCookie === '' && !Tools::login()) { | |
echo "ERROR: Login Failed\n"; | |
exit(1); | |
} | |
$autogenerateSku = Config::$skuPrefix === '' ? true : false; | |
$i = 1; | |
$keyForAddProduct = null; | |
$formKey = null; | |
$keyAndAction = null; | |
do { | |
if ($autogenerateSku) { | |
Config::$skuPrefix = md5(microtime()); | |
} | |
if ($formKey === null) { | |
$keyAndAction = Tools::getSaveProductKeyAndFormAction($keyForAddProduct); | |
$data = Tools::getSaveProductPostData($keyAndAction['key'], $autogenerateSku ? null : $i); | |
echo (new \DateTime())->format('Y-m-d H:i:s'), " - Saving: {$data['product']['sku']}\n"; | |
$ch = Tools::getHandle($keyAndAction['action']); | |
curl_setopt($ch, CURLOPT_POST, 1); | |
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data)); | |
$response = Tools::getResponseAndClose($ch); | |
$keyForAddProduct = Tools::findButtonKey($response, '\/catalog_product\/new'); | |
} else { | |
$data = Tools::getSaveProductPostData($formKey, $autogenerateSku ? null : $i); | |
echo (new \DateTime())->format('Y-m-d H:i:s'), " - Saving: {$data['product']['sku']}\n"; | |
$ch = Tools::getHandle($keyAndAction['action']); | |
curl_setopt($ch, CURLOPT_POST, 1); | |
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data)); | |
$response = Tools::getResponseAndClose($ch); | |
} | |
$formKey = Tools::findFormKey($response); | |
echo "\tsaved."; | |
if ($i <= Config::$productsToCreate) { | |
echo " ", (Config::$productsToCreate - $i), " SKUs remaining"; | |
} | |
echo "\n"; | |
} while (++$i <= Config::$productsToCreate); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment