yellow = $yellow;
$this->response = new YellowResponse($yellow);
$this->users = new YellowUsers($yellow);
$this->merge = new YellowMerge($yellow);
$this->yellow->config->setDefault("editLocation", "/edit/");
$this->yellow->config->setDefault("editUploadNewLocation", "/media/@group/@filename");
$this->yellow->config->setDefault("editUploadExtensions", ".gif, .jpg, .pdf, .png, .svg, .tgz, .zip");
$this->yellow->config->setDefault("editKeyboardShortcuts", "ctrl+b bold, ctrl+i italic, ctrl+e code, ctrl+k link, ctrl+s save, ctrl+shift+p preview");
$this->yellow->config->setDefault("editToolbarButtons", "auto");
$this->yellow->config->setDefault("editEndOfLine", "auto");
$this->yellow->config->setDefault("editUserFile", "user.ini");
$this->yellow->config->setDefault("editUserPasswordMinLength", "8");
$this->yellow->config->setDefault("editUserHashAlgorithm", "bcrypt");
$this->yellow->config->setDefault("editUserHashCost", "10");
$this->yellow->config->setDefault("editUserStatus", "active");
$this->yellow->config->setDefault("editUserHome", "/");
$this->yellow->config->setDefault("editLoginRestrictions", "0");
$this->yellow->config->setDefault("editLoginSessionTimeout", "2592000");
$this->yellow->config->setDefault("editBruteForceProtection", "25");
$this->users->load($this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile"));
}
// Handle startup
function onStartup($update)
{
if($update) $this->cleanCommand(array("clean", "all"));
}
// Handle request
function onRequest($scheme, $address, $base, $location, $fileName)
{
$statusCode = 0;
if($this->checkRequest($location))
{
$scheme = $this->yellow->config->get("serverScheme");
$address = $this->yellow->config->get("serverAddress");
$base = rtrim($this->yellow->config->get("serverBase").$this->yellow->config->get("editLocation"), '/');
list($scheme, $address, $base, $location, $fileName) = $this->yellow->getRequestInformation($scheme, $address, $base);
$this->yellow->page->setRequestInformation($scheme, $address, $base, $location, $fileName);
$statusCode = $this->processRequest($scheme, $address, $base, $location, $fileName);
}
return $statusCode;
}
// Handle page meta data parsing
function onParseMeta($page)
{
if($page==$this->yellow->page && $this->response->isActive())
{
if($this->response->isUser())
{
if(empty($this->response->rawDataSource)) $this->response->rawDataSource = $page->rawData;
if(empty($this->response->rawDataEdit)) $this->response->rawDataEdit = $page->rawData;
if(empty($this->response->rawDataEndOfLine)) $this->response->rawDataEndOfLine = $this->response->getEndOfLine($page->rawData);
if($page->statusCode==434) $this->response->rawDataEdit = $this->response->getRawDataNew($page->location);
}
if(empty($this->response->language)) $this->response->language = $page->get("language");
if(empty($this->response->action)) $this->response->action = $this->response->isUser() ? "none" : "login";
if(empty($this->response->status)) $this->response->status = "none";
if($this->response->status=="error") $this->response->action = "error";
}
}
// Handle page content parsing of custom block
function onParseContentBlock($page, $name, $text, $shortcut)
{
$output = null;
if($name=="edit" && $shortcut)
{
$editText = "$name $text";
if(substru($text, 0, 2)=="- ") $editText = trim(substru($text, 2));
$output = "get("pageEdit")."\">".htmlspecialchars($editText)."";
}
return $output;
}
// Handle page extra HTML data
function onExtra($name)
{
$output = null;
if($name=="header" && $this->response->isActive())
{
$pluginLocation = $this->yellow->config->get("serverBase").$this->yellow->config->get("pluginLocation");
$output = "\n";
$output .= "\n";
$output .= "\n";
}
return $output;
}
// Handle command
function onCommand($args)
{
list($command) = $args;
switch($command)
{
case "clean": $statusCode = $this->cleanCommand($args); break;
case "user": $statusCode = $this->userCommand($args); break;
default: $statusCode = 0;
}
return $statusCode;
}
// Handle command help
function onCommandHelp()
{
return "user [EMAIL PASSWORD NAME LANGUAGE]\n";
}
// Clean user accounts
function cleanCommand($args)
{
$statusCode = 0;
list($command, $path) = $args;
if($path=="all")
{
$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
if(!$this->users->clean($fileNameUser))
{
$statusCode = 500;
echo "ERROR cleaning configuration: Can't write file '$fileNameUser'!\n";
}
}
return $statusCode;
}
// Update user account
function userCommand($args)
{
$statusCode = 0;
list($command, $email, $password, $name, $language) = $args;
if(!empty($email) && !empty($password))
{
$userExisting = $this->users->isExisting($email);
$status = $this->getUserAccount($email, $password, $command);
switch($status)
{
case "invalid": echo "ERROR updating configuration: Please enter a valid email!\n"; break;
case "weak": echo "ERROR updating configuration: Please enter a different password!\n"; break;
}
if($status=="ok")
{
$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
$status = $this->users->update($fileNameUser, $email, $password, $name, $language, "active") ? "ok" : "error";
if($status=="error") echo "ERROR updating configuration: Can't write file '$fileNameUser'!\n";
}
if($status=="ok")
{
$algorithm = $this->yellow->config->get("editUserHashAlgorithm");
$status = substru($this->users->getHash($email), 0, 5)!="error-hash" ? "ok" : "error";
if($status=="error") echo "ERROR updating configuration: Hash algorithm '$algorithm' not supported!\n";
}
$statusCode = $status=="ok" ? 200 : 500;
echo "Yellow $command: User account ".($statusCode!=200 ? "not " : "");
echo ($userExisting ? "updated" : "created")."\n";
} else {
$statusCode = 200;
foreach($this->users->getData() as $line) echo "$line\n";
if(!$this->users->getNumber()) echo "Yellow $command: No user accounts\n";
}
return $statusCode;
}
// Process request
function processRequest($scheme, $address, $base, $location, $fileName)
{
$statusCode = 0;
if($this->checkUserAuth($scheme, $address, $base, $location, $fileName))
{
switch($_REQUEST["action"])
{
case "": $statusCode = $this->processRequestShow($scheme, $address, $base, $location, $fileName); break;
case "login": $statusCode = $this->processRequestLogin($scheme, $address, $base, $location, $fileName); break;
case "logout": $statusCode = $this->processRequestLogout($scheme, $address, $base, $location, $fileName); break;
case "settings": $statusCode = $this->processRequestSettings($scheme, $address, $base, $location, $fileName); break;
case "version": $statusCode = $this->processRequestVersion($scheme, $address, $base, $location, $fileName); break;
case "update": $statusCode = $this->processRequestUpdate($scheme, $address, $base, $location, $fileName); break;
case "create": $statusCode = $this->processRequestCreate($scheme, $address, $base, $location, $fileName); break;
case "edit": $statusCode = $this->processRequestEdit($scheme, $address, $base, $location, $fileName); break;
case "delete": $statusCode = $this->processRequestDelete($scheme, $address, $base, $location, $fileName); break;
case "preview": $statusCode = $this->processRequestPreview($scheme, $address, $base, $location, $fileName); break;
case "upload": $statusCode = $this->processRequestUpload($scheme, $address, $base, $location, $fileName); break;
}
} else if($this->checkUserUnauth($scheme, $address, $base, $location, $fileName)) {
$this->yellow->lookup->requestHandler = "core";
switch($_REQUEST["action"])
{
case "": $statusCode = $this->processRequestShow($scheme, $address, $base, $location, $fileName); break;
case "signup": $statusCode = $this->processRequestSignup($scheme, $address, $base, $location, $fileName); break;
case "forgot": $statusCode = $this->processRequestForgot($scheme, $address, $base, $location, $fileName); break;
case "confirm": $statusCode = $this->processRequestConfirm($scheme, $address, $base, $location, $fileName); break;
case "approve": $statusCode = $this->processRequestApprove($scheme, $address, $base, $location, $fileName); break;
case "recover": $statusCode = $this->processRequestRecover($scheme, $address, $base, $location, $fileName); break;
case "reactivate": $statusCode = $this->processRequestReactivate($scheme, $address, $base, $location, $fileName); break;
case "verify": $statusCode = $this->processRequestVerify($scheme, $address, $base, $location, $fileName); break;
case "change": $statusCode = $this->processRequestChange($scheme, $address, $base, $location, $fileName); break;
}
}
$this->checkUserFailed($scheme, $address, $base, $location, $fileName);
return $statusCode;
}
// Process request to show file
function processRequestShow($scheme, $address, $base, $location, $fileName)
{
$statusCode = 0;
if(is_readable($fileName))
{
$statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
} else {
if($this->yellow->lookup->isRedirectLocation($location))
{
$location = $this->yellow->lookup->isFileLocation($location) ? "$location/" : "/".$this->yellow->getRequestLanguage()."/";
$location = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, $location);
$statusCode = $this->yellow->sendStatus(301, $location);
} else {
$this->yellow->page->error($this->response->isUserRestrictions() ? 404 : 434);
$statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
}
}
return $statusCode;
}
// Process request for user login
function processRequestLogin($scheme, $address, $base, $location, $fileName)
{
$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
if($this->users->update($fileNameUser, $this->response->userEmail))
{
$home = $this->users->getHome($this->response->userEmail);
if(substru($location, 0, strlenu($home))==$home)
{
$location = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, $location);
$statusCode = $this->yellow->sendStatus(303, $location);
} else {
$location = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, $home);
$statusCode = $this->yellow->sendStatus(302, $location);
}
} else {
$this->yellow->page->error(500, "Can't write file '$fileNameUser'!");
$statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
}
return $statusCode;
}
// Process request for user logout
function processRequestLogout($scheme, $address, $base, $location, $fileName)
{
$this->response->userEmail = "";
$this->response->destroyCookies($scheme, $address, $base);
$location = $this->yellow->lookup->normaliseUrl(
$this->yellow->config->get("serverScheme"),
$this->yellow->config->get("serverAddress"),
$this->yellow->config->get("serverBase"), $location);
$statusCode = $this->yellow->sendStatus(302, $location);
return $statusCode;
}
// Process request for user signup
function processRequestSignup($scheme, $address, $base, $location, $fileName)
{
$this->response->action = "signup";
$this->response->status = "ok";
$name = trim(preg_replace("/[^\pL\d\-\. ]/u", "-", $_REQUEST["name"]));
$email = trim($_REQUEST["email"]);
$password = trim($_REQUEST["password"]);
if(empty($name) || empty($email) || empty($password)) $this->response->status = "incomplete";
if($this->response->status=="ok") $this->response->status = $this->getUserAccount($email, $password, $this->response->action);
if($this->response->status=="ok" && $this->response->isLoginRestrictions()) $this->response->status = "next";
if($this->response->status=="ok" && $this->users->isTaken($email)) $this->response->status = "next";
if($this->response->status=="ok")
{
$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
$this->response->status = $this->users->update($fileNameUser, $email, $password, $name, "", "unconfirmed") ? "ok" : "error";
if($this->response->status=="error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!");
}
if($this->response->status=="ok")
{
$this->response->status = $this->response->sendMail($scheme, $address, $base, $email, "confirm") ? "next" : "error";
if($this->response->status=="error") $this->yellow->page->error(500, "Can't send email on this server!");
}
$statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
return $statusCode;
}
// Process request to confirm user signup
function processRequestConfirm($scheme, $address, $base, $location, $fileName)
{
$this->response->action = "confirm";
$this->response->status = "ok";
$email = $_REQUEST["email"];
$this->response->status = $this->getUserStatus($email, $_REQUEST["action"]);
if($this->response->status=="ok")
{
$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
$this->response->status = $this->users->update($fileNameUser, $email, "", "", "", "unapproved") ? "ok" : "error";
if($this->response->status=="error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!");
}
if($this->response->status=="ok")
{
$this->response->status = $this->response->sendMail($scheme, $address, $base, $email, "approve") ? "done" : "error";
if($this->response->status=="error") $this->yellow->page->error(500, "Can't send email on this server!");
}
$statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
return $statusCode;
}
// Process request to approve user signup
function processRequestApprove($scheme, $address, $base, $location, $fileName)
{
$this->response->action = "approve";
$this->response->status = "ok";
$email = $_REQUEST["email"];
$this->response->status = $this->getUserStatus($email, $_REQUEST["action"]);
if($this->response->status=="ok")
{
$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
$this->response->status = $this->users->update($fileNameUser, $email, "", "", "", "active") ? "ok" : "error";
if($this->response->status=="error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!");
}
if($this->response->status=="ok")
{
$this->response->status = $this->response->sendMail($scheme, $address, $base, $email, "welcome") ? "done" : "error";
if($this->response->status=="error") $this->yellow->page->error(500, "Can't send email on this server!");
}
$statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
return $statusCode;
}
// Process request for forgotten password
function processRequestForgot($scheme, $address, $base, $location, $fileName)
{
$this->response->action = "forgot";
$this->response->status = "ok";
$email = trim($_REQUEST["email"]);
if(!filter_var($email, FILTER_VALIDATE_EMAIL)) $this->response->status = "invalid";
if($this->response->status=="ok" && !$this->users->isExisting($email)) $this->response->status = "next";
if($this->response->status=="ok")
{
$this->response->status = $this->response->sendMail($scheme, $address, $base, $email, "recover") ? "next" : "error";
if($this->response->status=="error") $this->yellow->page->error(500, "Can't send email on this server!");
}
$statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
return $statusCode;
}
// Process request to recover password
function processRequestRecover($scheme, $address, $base, $location, $fileName)
{
$this->response->action = "recover";
$this->response->status = "ok";
$email = trim($_REQUEST["email"]);
$password = trim($_REQUEST["password"]);
$this->response->status = $this->getUserStatus($email, $_REQUEST["action"]);
if($this->response->status=="ok")
{
if(empty($password)) $this->response->status = "password";
if($this->response->status=="ok") $this->response->status = $this->getUserAccount($email, $password, $this->response->action);
if($this->response->status=="ok")
{
$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
$this->response->status = $this->users->update($fileNameUser, $email, $password) ? "ok" : "error";
if($this->response->status=="error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!");
}
if($this->response->status=="ok")
{
$this->response->userEmail = "";
$this->response->destroyCookies($scheme, $address, $base);
$this->response->status = $this->response->sendMail($scheme, $address, $base, $email, "information") ? "done" : "error";
if($this->response->status=="error") $this->yellow->page->error(500, "Can't send email on this server!");
}
}
$statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
return $statusCode;
}
// Process request to reactivate account
function processRequestReactivate($scheme, $address, $base, $location, $fileName)
{
$this->response->action = "reactivate";
$this->response->status = "ok";
$email = $_REQUEST["email"];
$this->response->status = $this->getUserStatus($email, $_REQUEST["action"]);
if($this->response->status=="ok")
{
$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
$this->response->status = $this->users->update($fileNameUser, $email, "", "", "", "active") ? "done" : "error";
if($this->response->status=="error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!");
}
$statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
return $statusCode;
}
// Process request to change settings
function processRequestSettings($scheme, $address, $base, $location, $fileName)
{
$this->response->action = "settings";
$this->response->status = "ok";
$email = trim($_REQUEST["email"]);
$emailSource = $this->response->userEmail;
$password = trim($_REQUEST["password"]);
$name = trim(preg_replace("/[^\pL\d\-\. ]/u", "-", $_REQUEST["name"]));
$language = trim($_REQUEST["language"]);
if($email!=$emailSource || !empty($password))
{
if(empty($email)) $this->response->status = "invalid";
if($this->response->status=="ok") $this->response->status = $this->getUserAccount($email, $password, $this->response->action);
if($this->response->status=="ok" && $email!=$emailSource && $this->users->isTaken($email)) $this->response->status = "taken";
if($this->response->status=="ok" && $email!=$emailSource)
{
$pending = $emailSource;
$home = $this->users->getHome($emailSource);
$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
$this->response->status = $this->users->update($fileNameUser, $email, "no", $name, $language, "unverified", "", "", "", $pending, $home) ? "ok" : "error";
if($this->response->status=="error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!");
}
if($this->response->status=="ok")
{
$pending = $email.':'.(empty($password) ? $this->users->getHash($emailSource) : $this->users->createHash($password));
$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
$this->response->status = $this->users->update($fileNameUser, $emailSource, "", $name, $language, "", "", "", "", $pending) ? "ok" : "error";
if($this->response->status=="error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!");
}
if($this->response->status=="ok")
{
$action = $email!=$emailSource ? "verify" : "change";
$this->response->status = $this->response->sendMail($scheme, $address, $base, $email, $action) ? "next" : "error";
if($this->response->status=="error") $this->yellow->page->error(500, "Can't send email on this server!");
}
} else {
if($this->response->status=="ok")
{
$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
$this->response->status = $this->users->update($fileNameUser, $email, "", $name, $language) ? "done" : "error";
if($this->response->status=="error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!");
}
}
if($this->response->status=="done")
{
$location = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, $location);
$statusCode = $this->yellow->sendStatus(303, $location);
} else {
$statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
}
return $statusCode;
}
// Process request to verify email
function processRequestVerify($scheme, $address, $base, $location, $fileName)
{
$this->response->action = "verify";
$this->response->status = "ok";
$email = $emailSource = $_REQUEST["email"];
$this->response->status = $this->getUserStatus($email, $_REQUEST["action"]);
if($this->response->status=="ok")
{
$emailSource = $this->users->getPending($email);
if($this->users->getStatus($emailSource)!="active") $this->response->status = "done";
}
if($this->response->status=="ok")
{
$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
$this->response->status = $this->users->update($fileNameUser, $email, "", "", "", "unchanged") ? "ok" : "error";
if($this->response->status=="error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!");
}
if($this->response->status=="ok")
{
$this->response->status = $this->response->sendMail($scheme, $address, $base, $emailSource, "change") ? "done" : "error";
if($this->response->status=="error") $this->yellow->page->error(500, "Can't send email on this server!");
}
$statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
return $statusCode;
}
// Process request to change email or password
function processRequestChange($scheme, $address, $base, $location, $fileName)
{
$this->response->action = "change";
$this->response->status = "ok";
$email = $emailSource = trim($_REQUEST["email"]);
$this->response->status = $this->getUserStatus($email, $_REQUEST["action"]);
if($this->response->status=="ok")
{
list($email, $hash) = explode(':', $this->users->getPending($email), 2);
if(!$this->users->isExisting($email) || empty($hash)) $this->response->status = "done";
}
if($this->response->status=="ok" && $email!=$emailSource)
{
$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
$this->users->users[$emailSource]["pending"] = "none";
$this->response->status = $this->users->update($fileNameUser, $emailSource, "", "", "", "removed") ? "ok" : "error";
if($this->response->status=="error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!");
}
if($this->response->status=="ok")
{
$this->users->users[$email]["hash"] = $hash;
$this->users->users[$email]["pending"] = "none";
$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
$this->response->status = $this->users->update($fileNameUser, $email, "", "", "", "active") ? "ok" : "error";
if($this->response->status=="error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!");
}
if($this->response->status=="ok")
{
$this->response->userEmail = "";
$this->response->destroyCookies($scheme, $address, $base);
$this->response->status = $this->response->sendMail($scheme, $address, $base, $email, "information") ? "done" : "error";
if($this->response->status=="error") $this->yellow->page->error(500, "Can't send email on this server!");
}
$statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
return $statusCode;
}
// Process request to show software version
function processRequestVersion($scheme, $address, $base, $location, $fileName)
{
$this->response->action = "version";
$this->response->status = "ok";
if($this->yellow->plugins->isExisting("update"))
{
list($statusCodeCurrent, $dataCurrent) = $this->yellow->plugins->get("update")->getSoftwareVersion();
list($statusCodeLatest, $dataLatest) = $this->yellow->plugins->get("update")->getSoftwareVersion(true);
list($statusCodeModified, $dataModified) = $this->yellow->plugins->get("update")->getSoftwareModified();
$statusCode = max($statusCodeCurrent, $statusCodeLatest, $statusCodeModified);
if($this->response->isUserWebmaster())
{
foreach($dataCurrent as $key=>$value)
{
if(strnatcasecmp($dataCurrent[$key], $dataLatest[$key])<0)
{
++$updates;
if(!empty($this->response->rawDataOutput)) $this->response->rawDataOutput .= "
\n";
$this->response->rawDataOutput .= htmlspecialchars("$key $dataLatest[$key]");
}
}
if($updates==0)
{
foreach($dataCurrent as $key=>$value)
{
if(!is_null($dataModified[$key]) && !is_null($dataLatest[$key]))
{
$rawData = $this->yellow->text->getTextHtml("editVersionUpdateModified", $this->response->language)." - yellow->toolbox->normaliseArgs("option:force/feature:$key")."\">".$this->yellow->text->getTextHtml("editVersionUpdateForce", $this->response->language)."";
$rawData = preg_replace("/@software/i", htmlspecialchars("$key $dataLatest[$key]"), $rawData);
if(!empty($this->response->rawDataOutput)) $this->response->rawDataOutput .= "
\n";
$this->response->rawDataOutput .= $rawData;
}
}
}
} else {
foreach($dataCurrent as $key=>$value)
{
if(strnatcasecmp($dataCurrent[$key], $dataLatest[$key])<0) ++$updates;
}
}
$this->response->status = $updates ? "updates" : "done";
if($statusCode!=200) $this->response->status = "error";
}
$statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
return $statusCode;
}
// Process request to update website
function processRequestUpdate($scheme, $address, $base, $location, $fileName)
{
$statusCode = 0;
if($this->yellow->plugins->isExisting("update") && $this->response->isUserWebmaster())
{
$option = trim($_REQUEST["option"]);
$feature = trim($_REQUEST["feature"]);
$statusCode = $this->yellow->command("update", $option, $feature);
if($statusCode==200)
{
$location = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, $location);
$statusCode = $this->yellow->sendStatus(303, $location);
}
}
return $statusCode;
}
// Process request to create page
function processRequestCreate($scheme, $address, $base, $location, $fileName)
{
$statusCode = 0;
if(!$this->response->isUserRestrictions() && !empty($_REQUEST["rawdataedit"]))
{
$this->response->rawDataSource = $_REQUEST["rawdatasource"];
$this->response->rawDataEdit = $_REQUEST["rawdatasource"];
$this->response->rawDataEndOfLine = $_REQUEST["rawdataendofline"];
$rawData = $_REQUEST["rawdataedit"];
$page = $this->response->getPageNew($scheme, $address, $base, $location, $fileName, $rawData, $this->response->getEndOfLine());
if(!$page->isError())
{
if($this->yellow->toolbox->createFile($page->fileName, $page->rawData, true))
{
$location = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, $page->location);
$statusCode = $this->yellow->sendStatus(303, $location);
} else {
$this->yellow->page->error(500, "Can't write file '$page->fileName'!");
$statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
}
} else {
$this->yellow->page->error(500, $page->get("pageError"));
$statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
}
}
return $statusCode;
}
// Process request to edit page
function processRequestEdit($scheme, $address, $base, $location, $fileName)
{
$statusCode = 0;
if(!$this->response->isUserRestrictions() && !empty($_REQUEST["rawdataedit"]))
{
$this->response->rawDataSource = $_REQUEST["rawdatasource"];
$this->response->rawDataEdit = $_REQUEST["rawdataedit"];
$this->response->rawDataEndOfLine = $_REQUEST["rawdataendofline"];
$rawDataFile = $this->yellow->toolbox->readFile($fileName);
$page = $this->response->getPageEdit($scheme, $address, $base, $location, $fileName,
$this->response->rawDataSource, $this->response->rawDataEdit, $rawDataFile, $this->response->rawDataEndOfLine);
if(!$page->isError())
{
if($this->yellow->toolbox->renameFile($fileName, $page->fileName, true) &&
$this->yellow->toolbox->createFile($page->fileName, $page->rawData))
{
$location = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, $page->location);
$statusCode = $this->yellow->sendStatus(303, $location);
} else {
$this->yellow->page->error(500, "Can't write file '$page->fileName'!");
$statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
}
} else {
$this->yellow->page->error(500, $page->get("pageError"));
$statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
}
}
return $statusCode;
}
// Process request to delete page
function processRequestDelete($scheme, $address, $base, $location, $fileName)
{
$statusCode = 0;
if(!$this->response->isUserRestrictions() && is_file($fileName))
{
$this->response->rawDataSource = $_REQUEST["rawdatasource"];
$this->response->rawDataEdit = $_REQUEST["rawdatasource"];
$this->response->rawDataEndOfLine = $_REQUEST["rawdataendofline"];
$rawDataFile = $this->yellow->toolbox->readFile($fileName);
$page = $this->response->getPageDelete($scheme, $address, $base, $location, $fileName,
$rawDataFile, $this->response->rawDataEndOfLine);
if(!$page->isError())
{
if($this->yellow->lookup->isFileLocation($location))
{
if($this->yellow->toolbox->deleteFile($fileName, $this->yellow->config->get("trashDir")))
{
$location = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, $location);
$statusCode = $this->yellow->sendStatus(303, $location);
} else {
$this->yellow->page->error(500, "Can't delete file '$fileName'!");
$statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
}
} else {
if($this->yellow->toolbox->deleteDirectory(dirname($fileName), $this->yellow->config->get("trashDir")))
{
$location = $this->yellow->lookup->normaliseUrl($scheme, $address, $base, $location);
$statusCode = $this->yellow->sendStatus(303, $location);
} else {
$this->yellow->page->error(500, "Can't delete file '$fileName'!");
$statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
}
}
} else {
$this->yellow->page->error(500, $page->get("pageError"));
$statusCode = $this->yellow->processRequest($scheme, $address, $base, $location, $fileName, false);
}
}
return $statusCode;
}
// Process request to show preview
function processRequestPreview($scheme, $address, $base, $location, $fileName)
{
$page = $this->response->getPagePreview($scheme, $address, $base, $location, $fileName,
$_REQUEST["rawdataedit"], $_REQUEST["rawdataendofline"]);
$statusCode = $this->yellow->sendData(200, $page->outputData, "", false);
if(defined("DEBUG") && DEBUG>=1)
{
$parser = $page->get("parser");
echo "YellowEdit::processRequestPreview parser:$parser
\n";
}
return $statusCode;
}
// Process request to upload file
function processRequestUpload($scheme, $address, $base, $location, $fileName)
{
$data = array();
$fileNameTemp = $_FILES["file"]["tmp_name"];
$fileNameShort = preg_replace("/[^\pL\d\-\.]/u", "-", basename($_FILES["file"]["name"]));
$fileSizeMax = $this->yellow->toolbox->getNumberBytes(ini_get("upload_max_filesize"));
$extension = strtoloweru(($pos = strrposu($fileNameShort, '.')) ? substru($fileNameShort, $pos) : "");
$extensions = preg_split("/\s*,\s*/", $this->yellow->config->get("editUploadExtensions"));
if(!$this->response->isUserRestrictions() && is_uploaded_file($fileNameTemp) &&
filesize($fileNameTemp)<=$fileSizeMax && in_array($extension, $extensions))
{
$file = $this->response->getFileUpload($scheme, $address, $base, $location, $fileNameTemp, $fileNameShort);
if(!$file->isError() && $this->yellow->toolbox->renameFile($fileNameTemp, $file->fileName, true))
{
$data["location"] = $file->getLocation();
} else {
$data["error"] = "Can't write file '$file->fileName'!";
}
} else {
$data["error"] = "Can't write file '$fileNameShort'!";
}
$statusCode = $this->yellow->sendData(is_null($data["error"]) ? 200 : 500, json_encode($data), "a.json", false);
return $statusCode;
}
// Check request
function checkRequest($location)
{
$locationLength = strlenu($this->yellow->config->get("editLocation"));
$this->response->active = substru($location, 0, $locationLength)==$this->yellow->config->get("editLocation");
return $this->response->isActive();
}
// Check user authentication
function checkUserAuth($scheme, $address, $base, $location, $fileName)
{
if($this->isRequestSameSite("POST", $scheme, $address) || $_REQUEST["action"]=="")
{
if($_REQUEST["action"]=="login")
{
$email = $_REQUEST["email"];
$password = $_REQUEST["password"];
if($this->users->checkAuthLogin($email, $password))
{
$this->response->createCookies($scheme, $address, $base, $email);
$this->response->userEmail = $email;
$this->response->userRestrictions = $this->getUserRestrictions($email, $location, $fileName);
$this->response->language = $this->getUserLanguage($email);
} else {
$this->response->userFailedError = "login";
$this->response->userFailedEmail = $email;
$this->response->userFailedExpire = PHP_INT_MAX;
}
} else if(isset($_COOKIE["authtoken"]) && isset($_COOKIE["csrftoken"])) {
if($this->users->checkAuthToken($_COOKIE["authtoken"], $_COOKIE["csrftoken"], $_POST["csrftoken"], $_REQUEST["action"]==""))
{
$this->response->userEmail = $email = $this->users->getAuthEmail($_COOKIE["authtoken"]);
$this->response->userRestrictions = $this->getUserRestrictions($email, $location, $fileName);
$this->response->language = $this->getUserLanguage($email);
} else {
$this->response->userFailedError = "auth";
$this->response->userFailedEmail = $this->users->getAuthEmail($_COOKIE["authtoken"]);
$this->response->userFailedExpire = $this->users->getAuthExpire($_COOKIE["authtoken"]);
}
}
}
return $this->response->isUser();
}
// Check user without authentication
function checkUserUnauth($scheme, $address, $base, $location, $fileName)
{
$ok = false;
if($_REQUEST["action"]=="" || $_REQUEST["action"]=="signup" || $_REQUEST["action"]=="forgot")
{
$ok = true;
} else if(isset($_REQUEST["actiontoken"])) {
if($this->users->checkActionToken($_REQUEST["actiontoken"], $_REQUEST["email"], $_REQUEST["action"], $_REQUEST["expire"]))
{
$ok = true;
} else {
$this->response->userFailedError = "action";
$this->response->userFailedEmail = $_REQUEST["email"];
$this->response->userFailedExpire = $_REQUEST["expire"];
}
}
return $ok;
}
// Check user failed
function checkUserFailed($scheme, $address, $base, $location, $fileName)
{
if(!empty($this->response->userFailedError))
{
if($this->response->userFailedExpire>time() && $this->users->isExisting($this->response->userFailedEmail))
{
$email = $this->response->userFailedEmail;
$modified = $this->users->getModified($email);
$errors = $this->users->getErrors($email)+1;
$fileNameUser = $this->yellow->config->get("configDir").$this->yellow->config->get("editUserFile");
$status = $this->users->update($fileNameUser, $email, "", "", "", "", "", $modified, $errors) ? "ok" : "error";
if($status=="error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!");
if($errors==$this->yellow->config->get("editBruteForceProtection"))
{
$statusBeforeProtection = $this->users->getStatus($email);
$statusAfterProtection = ($statusBeforeProtection=="active" || $statusBeforeProtection=="inactive") ? "inactive" : "removed";
if($status=="ok")
{
$status = $this->users->update($fileNameUser, $email, "", "", "", $statusAfterProtection, "", $modified, $errors) ? "ok" : "error";
if($status=="error") $this->yellow->page->error(500, "Can't write file '$fileNameUser'!");
}
if($status=="ok" && $statusBeforeProtection=="active")
{
$status = $this->response->sendMail($scheme, $address, $base, $email, "reactivate") ? "done" : "error";
if($status=="error") $this->yellow->page->error(500, "Can't send email on this server!");
}
}
}
if($this->response->userFailedError=="login" || $this->response->userFailedError=="auth")
{
$this->response->destroyCookies($scheme, $address, $base);
$this->response->status = "error";
$this->yellow->page->error(430);
} else {
$this->response->status = "error";
$this->yellow->page->error(500, "Link has expired!");
}
}
}
// Return user status changes
function getUserStatus($email, $action)
{
switch($action)
{
case "confirm": $statusExpected = "unconfirmed"; break;
case "approve": $statusExpected = "unapproved"; break;
case "recover": $statusExpected = "active"; break;
case "reactivate": $statusExpected = "inactive"; break;
case "verify": $statusExpected = "unverified"; break;
case "change": $statusExpected = "active"; break;
}
return $this->users->getStatus($email)==$statusExpected ? "ok" : "done";
}
// Return user account changes
function getUserAccount($email, $password, $action)
{
$status = null;
foreach($this->yellow->plugins->plugins as $key=>$value)
{
if(method_exists($value["obj"], "onEditUserAccount"))
{
$status = $value["obj"]->onEditUserAccount($email, $password, $action, $this->users);
if(!is_null($status)) break;
}
}
if(is_null($status))
{
$status = "ok";
if(!empty($password) && strlenu($password)<$this->yellow->config->get("editUserPasswordMinLength")) $status = "weak";
if(!empty($email) && !filter_var($email, FILTER_VALIDATE_EMAIL)) $status = "invalid";
}
return $status;
}
// Return user restrictions
function getUserRestrictions($email, $location, $fileName)
{
$userRestrictions = null;
foreach($this->yellow->plugins->plugins as $key=>$value)
{
if(method_exists($value["obj"], "onEditUserRestrictions"))
{
$userRestrictions = $value["obj"]->onEditUserRestrictions($email, $location, $fileName, $this->users);
if(!is_null($userRestrictions)) break;
}
}
if(is_null($userRestrictions))
{
$userRestrictions = substru($location, 0, strlenu($this->users->getHome($email)))!=$this->users->getHome($email);
$userRestrictions |= empty($fileName) || strlenu(dirname($fileName))>128 || strlenu(basename($fileName))>128;
}
return $userRestrictions;
}
// Return user language
function getUserLanguage($email)
{
$language = $this->users->getLanguage($email);
if(!$this->yellow->text->isLanguage($language)) $language = $this->yellow->config->get("language");
return $language;
}
// Check if request came from same site
function isRequestSameSite($method, $scheme, $address)
{
if(preg_match("#^(\w+)://([^/]+)(.*)$#", $_SERVER["HTTP_REFERER"], $matches)) $origin = "$matches[1]://$matches[2]";
if(isset($_SERVER["HTTP_ORIGIN"])) $origin = $_SERVER["HTTP_ORIGIN"];
return $_SERVER["REQUEST_METHOD"]==$method && $origin=="$scheme://$address";
}
}
class YellowResponse
{
var $yellow; //access to API
var $plugin; //access to plugin
var $active; //location is active? (boolean)
var $userEmail; //user email
var $userRestrictions; //user can change page? (boolean)
var $userFailedError; //error of failed authentication
var $userFailedEmail; //email of failed authentication
var $userFailedExpire; //expiration time of failed authentication
var $rawDataSource; //raw data of page for comparison
var $rawDataEdit; //raw data of page for editing
var $rawDataOutput; //raw data of dynamic output
var $rawDataEndOfLine; //end of line format for raw data
var $language; //response language
var $action; //response action
var $status; //response status
function __construct($yellow)
{
$this->yellow = $yellow;
$this->plugin = $yellow->plugins->get("edit");
}
// Return new page
function getPageNew($scheme, $address, $base, $location, $fileName, $rawData, $endOfLine)
{
$page = new YellowPage($this->yellow);
$page->setRequestInformation($scheme, $address, $base, $location, $fileName);
$page->parseData($this->normaliseLines($rawData, $endOfLine), false, 0);
$this->editContentFile($page, "create");
if($this->yellow->lookup->isFileLocation($location) || $this->yellow->pages->find($page->location))
{
$page->location = $this->getPageNewLocation($page->rawData, $page->location, $page->get("pageNewLocation"));
$page->fileName = $this->yellow->lookup->findFileNew($page->location, $page->get("published"));
while($this->yellow->pages->find($page->location) || empty($page->fileName))
{
$rawData = $this->yellow->toolbox->setMetaData($page->rawData, "title", $this->getTitleNext($page->rawData));
$page->rawData = $this->normaliseLines($rawData, $endOfLine);
$page->location = $this->getPageNewLocation($page->rawData, $page->location, $page->get("pageNewLocation"));
$page->fileName = $this->yellow->lookup->findFileNew($page->location, $page->get("published"));
if(++$pageCounter>999) break;
}
if($this->yellow->pages->find($page->location) || empty($page->fileName))
{
$page->error(500, "Page '".$page->get("title")."' is not possible!");
}
} else {
$page->fileName = $this->yellow->lookup->findFileNew($page->location);
}
if($this->plugin->getUserRestrictions($this->userEmail, $page->location, $page->fileName))
{
$page->error(500, "Page '".$page->get("title")."' is restricted!");
}
return $page;
}
// Return modified page
function getPageEdit($scheme, $address, $base, $location, $fileName, $rawDataSource, $rawDataEdit, $rawDataFile, $endOfLine)
{
$page = new YellowPage($this->yellow);
$page->setRequestInformation($scheme, $address, $base, $location, $fileName);
$rawData = $this->plugin->merge->merge(
$this->normaliseLines($rawDataSource, $endOfLine),
$this->normaliseLines($rawDataEdit, $endOfLine),
$this->normaliseLines($rawDataFile, $endOfLine));
$page->parseData($this->normaliseLines($rawData, $endOfLine), false, 0);
$this->editContentFile($page, "edit");
if(empty($page->rawData)) $page->error(500, "Page has been modified by someone else!");
if($this->yellow->lookup->isFileLocation($location) && !$page->isError())
{
$pageSource = new YellowPage($this->yellow);
$pageSource->setRequestInformation($scheme, $address, $base, $location, $fileName);
$pageSource->parseData($this->normaliseLines($rawDataSource, $endOfLine), false, 0);
if(substrb($pageSource->rawData, 0, $pageSource->metaDataOffsetBytes) !=
substrb($page->rawData, 0, $page->metaDataOffsetBytes))
{
$page->location = $this->getPageNewLocation($page->rawData, $page->location, $page->get("pageNewLocation"));
$page->fileName = $this->yellow->lookup->findFileNew($page->location, $page->get("published"));
if($page->location!=$pageSource->location)
{
if(!$this->yellow->lookup->isFileLocation($page->location) || empty($page->fileName))
{
$page->error(500, "Page '".$page->get("title")."' is not possible!");
} else if($this->yellow->pages->find($page->location)) {
$page->error(500, "Page '".$page->get("title")."' already exists!");
}
}
}
}
if($this->plugin->getUserRestrictions($this->userEmail, $page->location, $page->fileName))
{
$page->error(500, "Page '".$page->get("title")."' is restricted!");
}
return $page;
}
// Return deleted page
function getPageDelete($scheme, $address, $base, $location, $fileName, $rawData, $endOfLine)
{
$page = new YellowPage($this->yellow);
$page->setRequestInformation($scheme, $address, $base, $location, $fileName);
$page->parseData($this->normaliseLines($rawData, $endOfLine), false, 0);
$this->editContentFile($page, "delete");
if($this->plugin->getUserRestrictions($this->userEmail, $page->location, $page->fileName))
{
$page->error(500, "Page '".$page->get("title")."' is restricted!");
}
return $page;
}
// Return preview page
function getPagePreview($scheme, $address, $base, $location, $fileName, $rawData, $endOfLine)
{
$page = new YellowPage($this->yellow);
$page->setRequestInformation($scheme, $address, $base, $location, $fileName);
$page->parseData($this->normaliseLines($rawData, $endOfLine), false, 200);
$this->yellow->text->setLanguage($page->get("language"));
$page->set("pageClass", "page-preview");
$page->set("pageClass", $page->get("pageClass")." template-".$page->get("template"));
$output = "