create new worksheet PHPExcel - php

I'm trying to create another worksheet and everything works fine. But what I need now is to create 1 depending on a variable. For instance :
I have two options one for validation and one for results.
Everything is conditioned by a boolean variable called $resultado.
I have my component in CakePHP
function ExcelCargaMasivaComponent() {
$this->xls = new PHPExcel();
$this->sheet = $this->xls->getActiveSheet();
$this->sheet->setTitle("Worksheet");
$this->sheet->getDefaultStyle()->getFont()->setName('Verdana');
$this->xls->createSheet();
$this->xls->setActiveSheetIndex(1);
$this->validations = $this->xls->getActiveSheet();
$this->validations->setTitle('Validations');
}
Where this-> validations is the second worksheet. Now, I need this worksheet has a different name, and therefore I want other data encapsulated in a function. So my function generate wanted condition this way:
function ExcelCargaMasivaComponent() {
$this->xls = new PHPExcel();
$this->sheet = $this->xls->getActiveSheet();
$this->sheet->setTitle("Worksheet");
$this->sheet->getDefaultStyle()->getFont()->setName('Verdana');
$this->xls->createSheet();
$this->xls->setActiveSheetIndex(1);
}
function generate($title = 'Report', $headers = array(), $data = array(), $uid = false, $resultados = false){
if($resultados){
$this->validations = $this->xls->getActiveSheet();
$this->validations->setTitle('Resultados');
}else{
$this->validations = $this->xls->getActiveSheet();
$this->validations->setTitle('Validations');
}
}
I do this so that the second sheet has a different name and different data depending on the variable, but I could not get it to work. I only generates 1 sheet with the title depending on the variable, it's not what I want.

Create new worksheet PHPExcel
Hi I really don't know if my answer may really do the magic to your question. However it seems fascinating to me.
Answer:
Just try doing the following to your generate method as I have provided the following code snippet:
function ExcelCargaMasivaComponent() {
$this->xls = new PHPExcel();
$this->sheet = $this->xls->getActiveSheet();
$this->sheet->setTitle("Worksheet");
$this->sheet->getDefaultStyle()->getFont()->setName('Verdana');
// $this->xls->createSheet(); // comment out this lines as we keep
// $this->xls->setActiveSheetIndex(1); // them in our generate method
}
function generate($title = 'Report', $headers = array(), $data = array(), $uid = false, $resultados = false) {
if ($resultados) {
$this->xls->createSheet(0);
$this->xls->setActiveSheetIndex(0); // This is the first required line
$this->validations = $this->xls->getActiveSheet();
$this->validations->setTitle('Resultados');
} else {
$this->xls->createSheet(1);
$this->xls->setActiveSheetIndex(1); // This is the second required line
$this->validations = $this->xls->getActiveSheet();
$this->validations->setTitle('Validations');
}
}
For your further reference please see the following SO Q&A Thread too.

Related

PHP: Script failing after PDO query

During my create user process I make a few queries to various database's to get the new user setup. This script has been working fine for about a year and a half, but now something is off.
So the first thing I do is I check to see if a user exists with the credentials being submitted. I've thoroughly tested the check and I'm confident my issue isn't there.
If that check comes back false then the script continues to create the user.
public function registerUser() {
parse_str($_SERVER['QUERY_STRING'], $data);
$data = (object) $data;
$check = json_decode($this->checkUserExists($data->email));
if ($check->res) {
$res = new \stdClass();
$res->res = false;
$res->user_status = $check->user_status;
$res->msg = 'User exists.';
echo json_encode($res);
}
if (!$check->res) {
$this->createUser($data);
}
}
The problem arises after all the queries have been completed, the script does not seem to want to run the if statement at the bottom. I marked it with comment characters so it's easier to find, but I included the entire function for clarity, maybe I'm doing something that is causing the issue.
I tried invoking an error manually at various points during the script. And I am able to trigger an error all the way down to the bottom of the script.
private function createUser($data) {
$Crypt = new CryptController();
$AuthSelect = new AuthController();
$Time = new TimeController();
$remote_address = new RemoteAddressController();
$Session = new SessionController();
$AuthInsert = new AuthModel_Insert();
$hashed_password = $Crypt->create_hash($data->password);
$data->password = '';
$AuthData = json_decode($AuthSelect->getAuth());
$system_auth_id = $AuthData->system_auth_id;
$user_id = $Crypt->get_uuid();
$user_auth_id = $Crypt->get_uuid();
$user_createddate = $Time->time();
$user_updateddate = $Time->time();
$user_lastupdateddate = $Time->time();
$agent_ip = $remote_address->getIpAddress();
$userData = $this->createUserObject(
$user_id,
$user_auth_id,
$system_auth_id,
$hashed_password,
$user_createddate,
$user_updateddate,
$user_lastupdateddate,
$data
);
$agentData = $this->createAgentObject(
$user_id,
$agent_ip,
$data
);
//////////////////////////////////////////
$create_user = $AuthInsert->createNewUser(
$userData
);
$create_user_agent = $this->setUserAgent(
$agentData
);
$sessionKeyData = new \stdClass();
$sessionKeyData->user_id = $user_id;
$sessionKeyData->user_auth_id = $user_auth_id;
$sessionKeyData->system_auth_id = $system_auth_id;
$sessionKeyData->agent_id = $create_user_agent->agent->agent_id;
$set_session_key = $Session->setSessionKey(
$sessionKeyData
);
$send_activation_email = $this->createUserActivation(
$userData
);
if (
$create_user &&
$create_user_agent->res &&
$set_session_key->res &&
$send_activation_email->res) {
$res = new \stdClass();
$res->res = true;
$res->msg = 'New user successfully created.';
echo json_encode($res);
} else {
$res = new \stdClass();
$res->res = false;
$res->msg = 'Error: User creation process incomplete.';
echo json_encode($res);
}
//////////////////////////////////////////
trigger_error("Invoked Error: ",E_USER_ERROR);
}
The queries themselves go through just fine, all the tables are populated just fine. The issue is that after that happens the script doesn't finish. It seems to end the createUser() function and return to the registerUser() function at which point the user will exist so it will return false and echo that back to the client.
In my testing it seems my issue might be at the bottom with that if statement. But I've tested each of those queries individually and they do return the desired booleans to get the true condition. But, even the false condition doesn't go through which should return 'Error: User creation process incomplete.'. That doesn't happen either.
I'm hoping someone sees something I'm missing because I've been stuck on this problem for too long. I appreciate any guidance that might lead me to an answer. Thanks in advance.
Just for clarification the message I'm getting back is $res->msg = 'User exists.'; which comes from registeruser(). The message I'm expecting back is $res->msg = 'New user successfully created.'; which should come from createUser().

craftcms 3 plugin which imports channel entries

I try to finish a plugin which imports data into my craftcms project. I already created a console based method/service, which I trigger/run in my shell. Inside my method(s) I receive data (XML or JSON) I parse my data and try to create and fill an entry of a specific channel I already created.
I tried "saveElement()" which doesn't work.
I found some tuts and informations for craftcms v2 (for example: https://docs.craftcms.com/api/v2/craft-entriesservice.html#public-methods)
Now i am stuck and i can not find any informations on how to solve this with craftcms v3.
Here is my last version of code after hours of different trys :(
$section = Craft::$app->sections->getSectionByHandle('testentry');
$entryTypes = $section->getEntryTypes();
$entryType = $entryTypes[0];
// Save Entry
//$entry = new EntryModel();
$entry = new \craft\elements\Entry();
$entry->sectionId = $section->id;
$entry->typeId = $entryType->id;
//$entry->locale = Craft::$app->i18n->getPrimarySiteLocaleId();
//$entry->authorId = 1; // TODO: Set author
$entry->enabled = true;
$entry->postDate = $post['post_date'];
$entry->slug = $post['post_name'];
// $entry->getContent()->title = $post['post_title'];
// $entry->setContentFromPost(array(
// 'body' => $postContent,
// 'categoryCareer' => NULL,
// ));
if (Craft::$app->elements->saveElement($entry)) {
$result = true;
}
else {
echo 'Could not save the Job entry.'."\n";
$result = false;
}

JSON is overwriting the old data how to keep on adding data with new ID

so, I am working on a JSON file that should keep on incrementing IDs.
However I get stuck at id:0 and when I insert new data the old data will be replaced by the new one (it keeps id:0).
I am not entirely sure what code is related and what not, so I will post whatever I think should be related and if someone with more knowledge related to JSON could adjust (in case it needs any) it, I would appreciate it a lot.
The include database_json.php contains the following code:
$databaseFile = file_get_contents('json_files/database.json');
$databaseJson = json_decode($databaseFile, true);
$database = $databaseJson['data'];
// below starts a new page, the page that submits the form called saveJson.php
include_once('database_json.php');
$data = $_POST;
//Setup an empty array.
$errors = array();
if (isset($data)) {
$newExerciseData = $data;
$exerciseArray = $data['main_object'];
$databaseFile = 'json_files/database.json';
$textContent = file_get_contents($databaseFile);
$database = json_decode($textContent, true);
if ($data['id'] === 'new') {
if (count($database['data']) == 0) {
$ID = 0;
} else {
$maxID = max($database['data']);
$ID = ++$maxID["id"];
}
$newJsonFile = 'jsonData_' . $ID . '.json';
$newJsonFilePath = 'json_files/' . $newJsonFile;
//Create new database exercise_txt
$newArrayData = array(
'id' => $ID,
// a lot of variables that aren't related to the problem
);
$database['data'][] = $newArrayData;
file_put_contents($databaseFile, json_encode($database, JSON_UNESCAPED_UNICODE, JSON_PRETTY_PRINT));
file_put_contents($newJsonFilePath, json_encode($newExerciseData, JSON_UNESCAPED_UNICODE, JSON_PRETTY_PRINT));
} else {
$index = array_search((int) $_POST['id'], array_column($database['data'], 'id'));
$correctJsonFile = 'json_files/jsonData_' . $_POST['id'] . '.json';
$newJsonFile = 'jsonData_' . $_POST['id'] . '.json';
$newJsonFilePath = 'json_files/' . $newJsonFile;
//Create new database exercise_txt
$newArrayData2 = array(
'id' => (int) $_POST['id'],
// more not related to problem variables
);
$database['data'][$index] = $newArrayData2;
file_put_contents($databaseFile, json_encode($database, JSON_UNESCAPED_UNICODE));
file_put_contents($newJsonFilePath, json_encode($newExerciseData, JSON_UNESCAPED_UNICODE));
}
echo json_encode($newExerciseData, JSON_UNESCAPED_UNICODE);
}
EDIT: someone wanted me to post how the JSON itself looked like... so this is how it looks:
The file is called: database.json
{
"data":
[
{
"id":0,
"exercisetitle":"Test300520180924",
"exerciseWord":["huiswerk"],
"syllables":["Huis","werk"],
"file":"jsonData_.json",
"audio":null,"language":null
}
]
}
(do not mind the audio and language, that's something for later on.
The best I could do was this, yes I read the stuff about making a post and how to properly format stuff etc. but I people would often say I need to include certain code etc etc. and it mostly would turn out messy as hell, so I would rather have a bit too much code (the code I think is related) then not have enough.
Cheers!

PHP getElementById not working

So I'm trying to write a short function using PHP to check whether a server (or the back up) is available. The service provides two servers to use, and a page within the server that simply has "OK" in an element with id "server_status". I basically took their code that they provided and adjusted it so that it provides the kind of output I need. I want to get an array of true or false (depending on whether one of the sites is available), and the correct page if it is. Right now the output every time is (false, "e404.html"), which is what I set it up to output if no conditions are met. Here is my code:
function checkURL() {
$servers = array('tpeweb.paybox.com', // primary URL
'tpeweb1.paybox.com'); // backup URL
foreach($servers as $server){
$doc = new DOMDocument();
$doc->loadHTMLFile('https://'.$server.'/load.html');
$server_status = "";
$element = $doc->getElementById('server_status');
if($element){
$server_status = $element->textContent;
}
if($server_status == "OK"){
// Server is up and services are available
return array(true, 'https://'.$server.'/cgi/MYchoix_pagepaiement.cgi');
}
}
return array(false, 'e404.html');
}
Doing some output testing, it appears that I'm loading the document into $doc, but it doesn't fill $element. I'm new to PHP so I'm not quite sure what is wrong.
EDIT:
This is the original code that the service provided to make this check, I adjusted it because I needed to be able to actually output the link to use:
<?php
$servers = array('urlserver.paybox.com', // primary URL
'urlserver1.paybox.com'); // backup URL
$serverOK = "";
foreach($servers as $server){
$doc = new DOMDocument();
$doc->loadHTMLFile('https://'.$server.'/load.html');
$server_status = "";
$element = $doc->getElementById('server_status');
if($element){
$server_status = $element->textContent;
}
if($server_status == "OK"){
// Server is up and services are available
$serverOK = $server;
break;
}
// else : Server is up but services are not available .
}
if(!$serverOK){
die("Error : no server found");
}
?>
//echo 'Connecting to https://'.$server.'/cgi/MYchoix_pagepaiement.cgi';
Thanks,
Adrian
Does your html file have a doctype declared?
from http://php.net/manual/en/domdocument.getelementbyid.php
For this function to work, you will need either to set some ID attributes with DOMElement::setIdAttribute or a DTD which defines an attribute to be of type ID.
It should be sufficient to include <!DOCTYPE html> at the very top of your html files, and set
$doc->validateOnParse = true; before calling the getElementByID function.

How can I minimize the amount of calls to the database?

I have lots of images into mysql database, which are painted so: <img src="/PrintImage.php?$id&width&height&quality" />.
The problem is that for each image, I am doing a call to the database through a class. To explain it better, here is the code:
edited: posted entirely class code
HTML View (example):
<img src="/PrintImage.php?id=10&width=120&height=120&quality=100" />
<img src="/PrintImage.php?id=20&width=120&height=120&quality=100" />
PrintImage.php
<?php
include_once($_SERVER['DOCUMENT_ROOT'].'/php/classes/Galerias.php');
$a = new \Galerias();
$i = $_GET['i'];
$w = $_GET['w'];
$h = $_GET['h'];
$q = $_GET['q'];
$a->Pintar($i, $w, $h, $q);
unset($a);
Gallery.php:
<?php
namespace Galerias;
include_once 'Database.php';
include_once 'Utils.php';
use \Database;
use \Utils;
class Galerias {
private $img_max_width = 1024;
private $img_max_height = 768;
private $img_quality = 85;
function __construct(){
$this->Database = new Database();
$this->Utils = new Utils();
}
public function Pintar($id, $width, $height, $quality){
$query = "select (select titulo from imagenes where id=$id) as titulo, (select imagen from imagenes where id=$id) as imagen";
$data = $this->Database->GetData($query);
$titulo = $data[0]['titulo'];
$tmp = $data[0]['imagen'];
$dataimg = $this->Utils->formatImage("string", $tmp, $width, $height, false);
$mime = $dataimg[1];
header("Content-type: $mime");
header("Content-Disposition: inline; filename=$titulo");
imagejpeg($dataimg[0], null, $quality);
}
}
Database.php:
<?php
namespace Database;
include_once 'Utils.php';
use \Utils;
class Database {
private $host = "localhost";
private $user = "user";
private $pass = "pass";
private $daba = "database";
private $link;
public $Utils;
function __construct(){
$this->Open();
$this->Utils = new Utils();
}
function __destruct(){
error_log('Database destruct');
}
private function Open(){
$this->link = mysql_connect($this->host, $this->user, $this->pass);
error_log('open succeeded');
mysql_select_db($this->daba, $this->link) or $this->Utils->newEx("Class Database->Open(): ".mysql_error());
}
private function Close(){
mysql_close($this->link) or $this->Utils->newEx("Class Database->Close(): ".mysql_error());
error_log('close succeeded');
}
public function GetData($query){
$data = array();
$query = mysql_query($query) or $this->Utils->newEx("Class Database->GetData(): ".mysql_error(), true);
while( $result = mysql_fetch_array($query) ){
$data[] = $result;
}
$this->FreeResults($query);
return $data;
}
public function InsertData($query){
if( !mysql_query($query) ){
$this->Utils->newEx("Class Database->InsertData(): ". mysql_error(), true);
return false;
}
return true;
}
public function DeleteData($query){
if( !mysql_query($query) ){
$this->Utils->newEx("Class Database->DeleteData(): ". mysql_error(), true);
return false;
}
return true;
}
public function FreeResults($res = null){
if( !is_null($res) ) mysql_free_result($res);
}
}
I am calling database too many times, because I have to load ~50/100 images per gallery.
The question is, how can I do this task efficiently? Thanks in advance
Your real question is: How can i minimize the amount of calls to the database.
The data is stored in the database so will have to do a call to retrieve the data. However what do you need to ask yourself, do i really need to ask the question every time?
In your current object model, you retrieve the unique data for every picture only when the object is created. This will add one call every time you want to read the info. This is a very common mistake to do and is something that (as you already realized) doesn't scale at all.
What you need is to make the object already have the data before the call. There is numerous ways to do this. Object Factories, Cached object, memcache, redis the list can be as long as there is active developers out there.
I'm inviting you to try to think outside the box and find a solution. Because if you understand the problem and solve it you will get a better grasp of object models and the pitfalls.
Lets take it again, are you sure you need to make the database call in the construction of the object? If you know the subset of the data you need, you should ask for in bulk. That will remove a lot of queries to the database.
Perhaps the Galerias could have function where you grab a lot of Pintar in one go?
I know this isn't a "do this" answer and probably will get down voted. But at least try :).
Also: Never use the query parameters $_GET $_POST directly without sanitize them first!!
Finally, I got the logical system to reduce -considerably- the amount of calls to the database. Before, I used a PHP file as image src to print images (with its headers, etc) directly from the database. This is a terrible fail. The problems to solve were:
I need to use a PHP file as image src, passing an ID, width, height and quality. And, of course, it has to be a friendly uri. So I can't use base64 encoding to print images. It has to be a PHP file (other file, other process, it isn't connected to the first one).
I use a shared hosting, the thinking of loading -nice- extensions like memcache is not viable.
Problem 2 tells me that I can't save images (or other data) in any place to use along the site. (It's wrong).
What I did (after thinking and searching and thinking...) is to use $_SESSION to store, previous serializing, all images. So, I solved all the problems. Now, have to look for a valid logic to populate the code. The result looks like this:
// Session Cache Class (static)
namespace SessionCache;
ini_set('memory_limit', '256M'); // this is the best issue of this system
session_start();
class SessionCache {
// todo: add the possible to expire the session
private static $SessionName = 'SessionCache';
public static function Check($name){
if( empty($_SESSION[self::$SessionName]) ) return false;
if( empty($_SESSION[self::$SessionName][$name]) ) return false;
else return true;
}
public static function Set($name, $data){
if( self::Check($name) ) return;
$data = serialize($data);
$_SESSION[self::$SessionName][$name] = $data;
}
public static function Get($name){
if( self::Check($name) ){
$data = unserialize($_SESSION[self::$SessionName][$name]);
return $data;
}
else return null;
}
public static function Flush($name){
if( self::Check($name) ) unset($_SESSION[self::$SessionName][$name]);
}
public static function Destroy(){
session_destroy();
}
}
Now, the (current) logic:
// Images Class. Here I use some extra stuff. Feel free to read the comments
namespace AdminPanel;
include_once 'SessionCache.php';
include_once 'Database.php';
include_once 'Utils.php';
use \AdminPanel\Database;
use \AdminPanel\Utils;
use SessionCache\SessionCache;
use stdClass;
class Patrocinios {
private $cache_name = 'Patrocinadores';
private $img_width = 225;
private $img_height = 70;
private $img_quality = 100;
public function __construct(){
$this->Database = new \AdminPanel\Database();
$this->Utils = new \AdminPanel\Utils();
}
private function CreateImageCache(){
if( SessionCache::Check($this->cache_name) ) return null;
$query = "select * from patrocinadores";
$this->Database->Open();
$data = $this->Database->GetData($query);
$this->Database->Close();
$patros = new stdClass();
if( count($data) > 0 ){
for( $i=0; $i<count($data); $i++ ){
$id = $data[$i]['id'];
$nombre = $data[$i]['nombre'];
$uri = $data[$i]['web'];
$mimetype = $data[$i]['tipo'];
$imagedata = $data[$i]['imagen'];
$patros->patro[$id] = new stdClass();
$patros->patro[$id]->id = $id;
$patros->patro[$id]->nombre = $nombre;
$patros->patro[$id]->uri = $uri;
$patros->patro[$id]->mimetype = $mimetype;
$patros->patro[$id]->data = $imagedata; // the image BLOB
}
}
SessionCache::Set($this->cache_name, $patros);
}
public function GetPatrocinadores(){ // this method is the only one called from the main view
$this->CreateImageCache();
$patros = SessionCache::Get($this->cache_name);
return $patros;
}
public function Pintar($id, $width, $height, $quality){ // this method is called from the PHP file used to print the images
if( !SessionCache::Check($this->cache_name) ) $patros = $this->GetPatrocinadores();
else $patros = SessionCache::Get($this->cache_name);
$dataimg = $this->Utils->formatImage("string", $patros->patro[$id]->data, $width, $height); // creates new image with desired measures and quality
header('Content-Type: '.$patros->patro[$id]->mimetype);
header('Content-Length: '.strlen($patros->patro[$id]->data));
imagejpeg($dataimg[0], null, $quality);
}
}
I just have a variable with the name of the session object ($cache_name). First I check if exists (from previous call). If not, I populate a stdClass() object with the information from the database and store it in the session.
<ul id="ulPatrocinadores">
<?php
include_once $_SERVER['DOCUMENT_ROOT'].'/php/classes/Patrocinios.php';
$p = new \AdminPanel\Patrocinios();
$patros = $p->GetPatrocinadores();
$str = '';
foreach( $patros as $value ){
foreach( $value as $patro ){
$id = $patro->id;
$nombre = str_replace(" ", "_", $patro->nombre);
$web = $patro->uri;
$str .= '<li>';
$str .= '<img src="/'.$nombre.'_pat-i='.$id.'&w=225&h=70&q=85" alt="'.$nombre.'" />';
}
}
echo $str;
?>
</ul>
Above is the main view which images are printed. Note that anchors and image sources goes to the PHP file that calls to the method Pintar(). I use a RewriteRule to redirect it.
<?php
include_once '../scripts/PrintPartner.php';
$a = new \AdminPanel\Patrocinios();
$i = $_GET['i'];
$w = $_GET['w'];
$h = $_GET['h'];
$q = $_GET['q'];
$a->Pintar($i, $w, $h, $q);
unset($a);
And so, I finally achieve it. I don't know if this is a good system because $_SESSION is relational to php memory_limit, but after two days of thinking about it, I couldn't get something better.
What I achieve:
Before: one query for each image to the database. Now: one query for all images for one session (or the time that I could need).
Keep of the friendly uris with creating of the image file on the fly as needed, still using a PHP file as image src.
A good system to reduce calls to the database, also using a shared hosting.
Hope this experience helps someone.

Categories