// Write new filename back to client on success } else { if ($command === "Remove") { $paths = null; $file = SMEnvironment::GetPostValue("File"); $files = SMEnvironment::GetPostValue("Files"); if ($file !== null) { $paths = array($file); } else { if ($files !== null) { $paths = explode(";", $files); } } if ($paths === null) { header("HTTP/1.1 500 Internal Server Error"); echo "Error - unable to remove files - no path(s) given"; exit; } foreach ($paths as $path) { // Make sure $path is a safe path (e.g. does not contain ../../), and make sure the file referenced is found in $imagesFolder if (SMStringUtilities::Validate($path, SMValueRestriction::$SafePath) === false || strpos($path, $imagesFolder) !== 0) { header("HTTP/1.1 500 Internal Server Error"); echo "Error - unsafe path '" . $path . "' detected"; exit; } if (SMFileSystem::FileExists($path) === true) { SMFileSystem::Delete($path); } } } }
public function InitComplete() { // Add basket and product categories to link pickers if ($this->smMenuExists === true && SMMenuLinkList::GetInstance()->GetReadyState() === true) { $ds = new SMDataSource("SMShopProducts"); $products = $ds->Select("Category, CategoryId", "", "Category ASC"); $menuLinkList = SMMenuLinkList::GetInstance(); $added = array(); foreach ($products as $prod) { if (in_array($prod["CategoryId"], $added, true) === true) { continue; } $menuLinkList->AddLink($this->getTranslation("Title"), $prod["Category"], "shop/" . $prod["CategoryId"]); $added[] = $prod["CategoryId"]; } } if ($this->smPagesExists === true && SMPagesLinkList::GetInstance()->GetReadyState() === true) { $ds = new SMDataSource("SMShopProducts"); $products = $ds->Select("Category, CategoryId", "", "Category ASC"); $pagesLinkList = SMPagesLinkList::GetInstance(); $added = array(); foreach ($products as $prod) { if (in_array($prod["CategoryId"], $added, true) === true) { continue; } $pagesLinkList->AddLink($this->getTranslation("Title"), $prod["Category"], "shop/" . $prod["CategoryId"]); $added[] = $prod["CategoryId"]; } } // Load JS and CSS resources SMEnvironment::GetMasterTemplate()->RegisterResource(SMTemplateResource::$JavaScript, SMExtensionManager::GetExtensionPath($this->name) . "/JSShop/Fit.UI/Fit.UI.js"); SMEnvironment::GetMasterTemplate()->RegisterResource(SMTemplateResource::$StyleSheet, SMExtensionManager::GetExtensionPath($this->name) . "/JSShop/Fit.UI/Fit.UI.css", true); SMEnvironment::GetMasterTemplate()->RegisterResource(SMTemplateResource::$JavaScript, SMExtensionManager::GetExtensionPath($this->name) . "/JSShop/JSShop.js"); // Prepare callbacks $basePath = SMEnvironment::GetInstallationPath(); // Use full path to prevent problems when calling WebServices under /shop/XYZ which would be redirected to / without preserving POST data (htaccess) $basePath .= $basePath !== "/" ? "/" : ""; $dsCallback = $basePath . SMExtensionManager::GetCallbackUrl($this->name, "Callbacks/DataSource"); $fsCallback = $basePath . SMExtensionManager::GetCallbackUrl($this->name, "Callbacks/Files"); $payCallback = $basePath . SMExtensionManager::GetCallbackUrl($this->name, "Callbacks/Payment"); // Prepare language $langCode = SMLanguageHandler::GetSystemLanguage(); $shopLang = SMFileSystem::FileExists(dirname(__FILE__) . "/JSShop/Languages/" . $langCode . ".js") === true ? $langCode : "en"; // Prepare cookie store $cookiePrefix = SMEnvironment::IsSubSite() === false ? "SMRoot" : ""; // Prevent cookies on root site from causing naming conflicts with cookies on subsites $cookiePath = SMEnvironment::GetInstallationPath(); // Prevent /shop virtual directory from being used as cookie path when adding products to basket by forcing cookie path // Prepare payment modules $paymentMethodsStr = SMAttributes::GetAttribute("SMShopPaymentMethods") !== null ? SMAttributes::GetAttribute("SMShopPaymentMethods") : ""; if ($paymentMethodsStr !== "") { $paymentMethods = explode(";", $paymentMethodsStr); $paymentMethodsStr = ""; $paymentModule = null; foreach ($paymentMethods as $pm) { $paymentModule = explode("=", $pm); // 0 = PSPI module name, 1 = title if (count($paymentModule) !== 2) { continue; } // Not valid $paymentMethodsStr .= $paymentMethodsStr !== "" ? ", " : ""; $paymentMethodsStr .= "{ Module: '" . $paymentModule[0] . "', Title: '" . $paymentModule[1] . "' }"; } } // Configure JSShop $jsInit = "\n\t\t<script type=\"text/javascript\">\n\t\tJSShop.Settings.ShippingExpenseExpression = \"" . (SMAttributes::GetAttribute("SMShopShippingExpenseExpression") !== null ? SMAttributes::GetAttribute("SMShopShippingExpenseExpression") : "") . "\";\n\t\tJSShop.Settings.ShippingExpenseVat = " . (SMAttributes::GetAttribute("SMShopShippingExpenseVat") !== null && SMAttributes::GetAttribute("SMShopShippingExpenseVat") !== "" ? SMAttributes::GetAttribute("SMShopShippingExpenseVat") : "0") . ";\n\t\tJSShop.Settings.ShippingExpenseMessage = \"" . (SMAttributes::GetAttribute("SMShopShippingExpenseMessage") !== null ? SMAttributes::GetAttribute("SMShopShippingExpenseMessage") : "") . "\";\n\t\tJSShop.Settings.BasketUrl = \"" . SMExtensionManager::GetExtensionUrl($this->name) . "&SMShopBasket" . "\";\n\t\tJSShop.Settings.TermsUrl = \"" . (SMAttributes::GetAttribute("SMShopTermsPage") !== null ? SMAttributes::GetAttribute("SMShopTermsPage") : "") . "\";\n\t\tJSShop.Settings.PaymentUrl = \"" . $payCallback . "\";\n\t\tJSShop.Settings.PaymentMethods = [ " . $paymentMethodsStr . " ];\n\n\t\tJSShop.Language.Name = \"" . $shopLang . "\";\n\n\t\tJSShop.Cookies.Prefix(\"" . $cookiePrefix . "\" + JSShop.Cookies.Prefix());\n\t\tJSShop.Cookies.Path(\"" . $cookiePath . "\");\n\n\t\tJSShop.WebService.Products.Create = \"" . $dsCallback . "\";\n\t\tJSShop.WebService.Products.Retrieve = \"" . $dsCallback . "\";\n\t\tJSShop.WebService.Products.RetrieveAll = \"" . $dsCallback . "\";\n\t\tJSShop.WebService.Products.Update = \"" . $dsCallback . "\";\n\t\tJSShop.WebService.Products.Delete = \"" . $dsCallback . "\";\n\n\t\tJSShop.WebService.Files.Upload = \"" . $fsCallback . "\"; // Expected to respond with file path on server\n\t\tJSShop.WebService.Files.Remove = \"" . $fsCallback . "\";\n\n\t\tJSShop.WebService.Orders.Create = \"" . $dsCallback . "\";\n\t\tJSShop.WebService.Orders.Retrieve = \"" . $dsCallback . "\";\n\t\tJSShop.WebService.Orders.RetrieveAll = \"" . $dsCallback . "\";\n\t\tJSShop.WebService.Orders.Update = \"" . $dsCallback . "\";\n\t\tJSShop.WebService.Orders.Delete = \"" . $dsCallback . "\";\n\n\t\tJSShop.WebService.OrderEntries.Create = \"" . $dsCallback . "\";\n\t\tJSShop.WebService.OrderEntries.Retrieve = \"" . $dsCallback . "\";\n\t\tJSShop.WebService.OrderEntries.RetrieveAll = \"" . $dsCallback . "\";\n\t\tJSShop.WebService.OrderEntries.Update = \"" . $dsCallback . "\";\n\t\tJSShop.WebService.OrderEntries.Delete = \"" . $dsCallback . "\";\n\n\t\tJSShop.Events.OnRequest = function(request, models, operation)\n\t\t{\n\t\t\t// Unicode encode data\n\n\t\t\tvar data = request.GetData();\n\t\t\tvar properties = data.Properties;\n\n\t\t\tFit.Array.ForEach(properties, function(prop)\n\t\t\t{\n\t\t\t\tif (typeof(properties[prop]) === \"string\")\n\t\t\t\t\tproperties[prop] = SMStringUtilities.UnicodeEncode(properties[prop]);\n\t\t\t});\n\n\t\t\t// Product model: Create URL friendly category name\n\n\t\t\tif ((operation === \"Create\" || operation === \"Update\") && Fit.Core.InstanceOf(models[0], JSShop.Models.Product) === true)\n\t\t\t{\n\t\t\t\tvar category = properties[\"Category\"];\n\t\t\t\tvar catId = category;\n\n\t\t\t\tcatId = catId.replace(/ /g, \"_\"); // Replace spaces with underscores\n\n\t\t\t\t// Support alternatives to danish characters\n\t\t\t\tcatId = catId.replace(/Æ/g, \"Ae\");\n\t\t\t\tcatId = catId.replace(/æ/g, \"ae\");\n\t\t\t\tcatId = catId.replace(/Ø/g, \"Eo\");\n\t\t\t\tcatId = catId.replace(/ø/g, \"oe\");\n\t\t\t\tcatId = catId.replace(/Å/g, \"Aa\");\n\t\t\t\tcatId = catId.replace(/å/g, \"aa\");\n\n\t\t\t\tcatId = catId.replace(/[^A-Za-z0-9_-]/g, \"\"); // Remove invalid characters (^ in a range means NOT)\n\n\t\t\t\tif (catId !== category)\n\t\t\t\t{\n\t\t\t\t\t// Two different categories can end up with the same Category ID, e.g. XæYæZ and X.Y.Z = XYZ.\n\t\t\t\t\t// This will especially be true if categories only consists of invalid characters (unicode),\n\t\t\t\t\t// in which case the Category ID will now be empty. Therefore, a hash code representing the\n\t\t\t\t\t// name of the category is used to create a unique and valid Category ID.\n\n\t\t\t\t\tvar hash = Fit.String.Hash(category);\n\t\t\t\t\tcatId = ((catId !== \"\") ? catId : \"cat\") + \"-\" + ((hash < 0) ? \"m\" : \"\") + Math.abs(hash);\n\t\t\t\t}\n\n\t\t\t\tproperties[\"CategoryId\"] = catId; // NOTICE: CategoryId is NOT defined in Product model, only here in JSON data\n\t\t\t}\n\n\t\t\trequest.SetData(data);\n\t\t};\n\n\t\tJSShop.Events.OnSuccess = function(request, models, operation)\n\t\t{\n\t\t\tif (operation === \"Retrieve\" || operation === \"RetrieveAll\")\n\t\t\t{\n\t\t\t\t// Decode unicode encoded data\n\n\t\t\t\tFit.Array.ForEach(models, function(model)\n\t\t\t\t{\n\t\t\t\t\tvar properties = model.GetProperties();\n\n\t\t\t\t\tFit.Array.ForEach(properties, function(prop)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (typeof(properties[prop]) === \"string\")\n\t\t\t\t\t\t\tmodel[prop](SMStringUtilities.UnicodeDecode(model[prop]())); // Never manipulate properties directly - using Setter function\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t}\n\t\t};\n\t\tJSShop.Events.OnError = function(request, models, operation)\n\t\t{\n\t\t\tFit.Controls.Dialog.Alert('WebService communication failed (' + operation + '):<br><br>' + request.GetResponseText().replace(\"<pre>\", \"<pre style='overflow: auto'>\"));\n\t\t};\n\t\t</script>\n\t\t"; SMEnvironment::GetMasterTemplate()->AddToHeadSection($jsInit); }