I've got an array with specifications. I want each specification to become a column. I am having trouble with working this out though.
$specifications = new Specifications();
$columnCounter = 1;
foreach ($specifications as $specificationId => $specification) {
$column = PHPExcel_Cell::getColumnByNumber($columnCounter);
$objPHPExcel
->getActiveSheet()
->getColumnDimension($column)
->setAutoSize(true)
;
$objPHPExcel->setActiveSheetIndex(0)
->setCellValue($column.'1', $specification['value'])
;
$columnCounter++;
}
The PHPExcel::getColumnByNumber() is of course an imaginary function. Though I am wondering how others do this and how best to address this.
$book = new PHPExcel();
$book->setActiveSheetIndex(0);
$sheet = $book->getActiveSheet();
$sheet->setTitle('Sets');
$xls_row = 5;
$xls_col = 3;
foreach($specifications as $specificationId => &$specification)
{
$adr = coord($xls_row, $xls_col);
$sheet->setCellValueExplicit($adr, $specification->title, PHPExcel_Cell_DataType::TYPE_STRING);
$sheet->getColumnDimension(coord_x($xls_col))->setAutoSize(true);
$xls_col++;
}
// convert a 0-based coordinate value into EXCEL B1-format
function coord_x($x)
{
if($x<26) $x = chr(ord('A')+$x);
else
{
$x -= 26;
$c1 = $x % 26;
$c2 = intval(($x - $c1)/26);
$x = chr(ord('A')+$c2).chr(ord('A')+$c1);
}
return $x;
}
// convert X,Y 0-based cell address into EXCEL B1-format pair
function coord($y,$x)
{
return coord_x($x).($y+1);
}
Related
I am trying to use TCPDF library to have a PDF file that supports Arabic letters. I have created a table and get the data from MYSQL database.
<?php
// Include the main TCPDF library (search for installation path).
require_once('TCPDF/config/tcpdf_config.php');
require_once('TCPDF/tcpdf.php');
class PDF extends TCPDF{
var $tablewidths;
var $headerset;
var $footerset;
function morepagestable($lineheight=8) {
// some things to set and 'remember'
$l = $this->lMargin*2;
$startheight = $h = $this->GetY();
$startpage = $currpage = $this->page;
// calculate the whole width
foreach($this->tablewidths as $width) {
$fullwidth += $width;
}
// Now let's start to write the table
$row = 0;
while($data=mysql_fetch_row($this->results)) {
$this->page = $currpage;
// write the horizontal borders
$this->Line($l,$h,$fullwidth+$l,$h);
// write the content and remember the height of the highest col
foreach($data as $col => $txt) {
$this->page = $currpage;
$this->SetXY($l,$h);
$this->MultiCell($this->tablewidths[$col],$lineheight,$txt,0,$this->colAlign[$col]);
$l += $this->tablewidths[$col];
if($tmpheight[$row.'-'.$this->page] < $this->GetY()) {
$tmpheight[$row.'-'.$this->page] = $this->GetY();
}
if($this->page > $maxpage)
$maxpage = $this->page;
unset($data[$col]);
}
// get the height we were in the last used page
$h = $tmpheight[$row.'-'.$maxpage];
// set the "pointer" to the left margin
$l = $this->lMargin*2;
// set the $currpage to the last page
$currpage = $maxpage;
unset($datas[$row]);
$row++ ;
}
// draw the borders
// we start adding a horizontal line on the last page
$this->page = $maxpage;
$this->Line($l,$h,$fullwidth+$l,$h);
// now we start at the top of the document and walk down
for($i = $startpage; $i <= $maxpage; $i++) {
$this->page = $i;
$l = $this->lMargin*2;
$t = ($i == $startpage) ? $startheight : $this->tMargin;
$lh = ($i == $maxpage) ? $h : $this->h-$this->bMargin;
$this->Line($l,$t,$l,$lh);
foreach($this->tablewidths as $width) {
$l += $width;
$this->Line($l,$t,$l,$lh);
}
}
// set it to the last page, if not it'll cause some problems
$this->page = $maxpage;
}
connect($host='xxxx',$username='xxxx',$passwd='xxxx',$db='xxxxx')
{
$this->conn = mysql_connect($host,$username,$passwd) or die( mysql_error() );
mysql_select_db($db,$this->conn) or die( mysql_error() );
return true;
}
function query($query){
$this->results = mysql_query($query,$this->conn);
$this->numFields = mysql_num_fields($this->results);
}
function mysql_report($query,$dump=false,$attr=array()){
foreach($attr as $key=>$val){
$this->$key = $val ;
}
$this->query($query);
// if column widths not set
if(!isset($this->tablewidths)){
// starting col width
$this->sColWidth = (($this->w-$this->lMargin*2-$this->rMargin))/$this->numFields;
// loop through results header and set initial col widths/ titles/ alignment
// if a col title is less than the starting col width / reduce that column size
for($i=0;$i<$this->numFields;$i++){
$stringWidth = $this->getstringwidth(mysql_field_name($this->results,$i)) + 8 ;
if( ($stringWidth) < $this->sColWidth){
$colFits[$i] = $stringWidth ;
// set any column titles less than the start width to the column title width
}
$this->colTitles[$i] = mysql_field_name($this->results,$i) ;
switch (mysql_field_type($this->results,$i)){
case 'int':
$this->colAlign[$i] = 'L';
break;
default:
$this->colAlign[$i] = 'L';
}
}
// loop through the data, any column whose contents is bigger that the col size is
// resized
while($row=mysql_fetch_row($this->results)){
foreach($colFits as $key=>$val){
$stringWidth = $this->getstringwidth($row[$key]) + 6 ;
if( ($stringWidth) > $this->sColWidth ){
// any col where row is bigger than the start width is now discarded
unset($colFits[$key]);
}else{
// if text is not bigger than the current column width setting enlarge the column
if( ($stringWidth) > $val ){
$colFits[$key] = ($stringWidth) ;
}
}
}
}
foreach($colFits as $key=>$val){
// set fitted columns to smallest size
$this->tablewidths[$key] = $val;
// to work out how much (if any) space has been freed up
$totAlreadyFitted += $val;
}
$surplus = (sizeof($colFits)*$this->sColWidth) - ($totAlreadyFitted);
for($i=0;$i<$this->numFields;$i++){
if(!in_array($i,array_keys($colFits))){
$this->tablewidths[$i] = $this->sColWidth + ($surplus/(($this->numFields)-sizeof($colFits)));
}
}
ksort($this->tablewidths);
if($dump){
Header('Content-type: text/plain');
for($i=0;$i<$this->numFields;$i++){
if(strlen(mysql_field_name($this->results,$i))>$flength){
$flength = strlen(mysql_field_name($this->results,$i));
}
}
switch($this->k){
case 72/25.4:
$unit = 'millimeters';
break;
case 72/2.54:
$unit = 'centimeters';
break;
case 72:
$unit = 'inches';
break;
default:
$unit = 'points';
}
print "All measurements in $unit\n\n";
for($i=0;$i<$this->numFields;$i++){
printf("%-{$flength}s : %-10s : %10f\n",
mysql_field_name($this->results,$i),
mysql_field_type($this->results,$i),
$this->tablewidths[$i] );
}
print "\n\n";
print "\$pdf->tablewidths=\n\tarray(\n\t\t";
for($i=0;$i<$this->numFields;$i++){
($i<($this->numFields-1)) ?
print $this->tablewidths[$i].", /* ".mysql_field_name($this->results,$i)." */ \n\t\t":
print $this->tablewidths[$i]." /* ".mysql_field_name($this->results,$i)." */\n\t\t";
}
print "\n\t);\n";
exit;
}
} else { // end of if tablewidths not defined
for($i=0;$i<$this->numFields;$i++){
$this->colTitles[$i] = mysql_field_name($this->results,$i) ;
switch (mysql_field_type($this->results,$i)){
case 'int':
$this->colAlign[$i] = 'R';
break;
default:
$this->colAlign[$i] = 'L';
}
}
}
mysql_data_seek($this->results,0);
$this->Open();
$this->setY($this->tMargin);
$this->AddPage();
$this->morepagestable($this->FontSizePt);
$this->Output();
}
}
$pdf = new PDF(PDF_PAGE_ORIENTATION,PDF_UNIT,PDF_PAGE_FORMAT,true, 'UTF- 8', false);
$pdf->SetFont('aealarabiya', '', 14, '', false);
$pdf->connect('xxxxxxxxxx','xxxxxxxxxxxxxx','xxxxxxxxxxxxx','xxxxxxxxxxxxx');
$attr=array('titleFontSize'=>24,'titleText'=>'THIS IS MY PDF FILE');
$pdf->mysql_report("SELECT * FROM Student_Table",false,$attr);
?>
I am OK with the table that is created with my code. The Arabic data retrieved is as the following?how can I solve it ?
Your problem is very simple bro, you need to choose the correct database encoding and do the query with it , but before going for that , I think this is my duty to tell you YOU DON'T HAVE TO USE "mysql" YOU HAVE TO USE "mysqli" ,now let us solve the problem :
set your database encoding to (utf8_general_ci). take a backup don't forget all the old stuff will be destroyed if you change the charset of the database do this if it's new or empty
after mysqli connect do this $db->set_charset("utf8"); or if you still
want to work with mysql use this mysql_set_charset("utf8");
Here is the edited code:
connect($host='xxxx',$username='xxxx',$passwd='xxxx',$db='xxxxx')
{
$this->conn = mysql_connect($host,$username,$passwd) or die( mysql_error() );
mysql_select_db($db,$this->conn) or die( mysql_error() );
mysql_set_charset("utf8");
return true;
}
But, like what i told you , you did it in wrong way , use mysqli and do it with full OOP not some time and in other Not !
I'm writing an export to excel & have a dynamic number of columns, i.e. I won't know how many columns will be needed before I run the query so I need to dynamically assign the column numbers like below:
$objPHPExcel->setActiveSheetIndex(0)
->setCellValue('A1', 'value')
->setCellValue('A2', 'value')
->setCellValue('B2', 'value')
->setCellValue('C2', 'value')
//...etc...
->setCellValue('AA2', 'value')
->setCellValue('AB2', 'value')
->setCellValue('AC2', 'value')
//...etc...
how can I do this with php?
UPDATE
sorry, the column naming pattern is:
A, B, C, .. AA, AB, AC ... BA, BB, BC... etc, the number suffix is actually the row. and no, the 'value would actually be populated from some query data setting my values would look more like:
$i=1;
while($result= $query->fetch_assoc()){
->setCellValue($col.$i, $result['whatever'])
$i++;
}
I just don't know how to get the column letters to increment in that pattern.
Simplest answer is
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
echo Coordinate::stringFromColumnIndex(5) // return E
echo Coordinate::columnIndexFromString('AA') // returns 27
Optimized Function
function columnFromIndex($number){
if($number === 0)
return "A";
$name='';
while($number>0){
$name=chr(65+$number%26).$name;
$number=intval($number/26)-1;
if($number === 0){
$name="A".$name;
break;
}
}
return $name;
}
If you don't know how many columns/rows you're going to be working with in advance, how can you expect to use the fluent interface in this way?
Following your edit of the question, you might do something like:
$i = 1;
while($result = $query->fetch_assoc()){
$col = 'A';
foreach($result as $value) {
$objPHPExcel->getActiveSheet()->setCellValue($col++.$i, $value);
}
$i++;
}
However, you might consider taking another approach, and using the fromArray() method to populate your data
$i = 1;
while($result = $query->fetch_assoc()){
$objPHPExcel->getActiveSheet()->fromArray('A'.$i++, $result);
}
Maybe so late, and i dont know if there's a better solution but, i make this recursive function to solve this problem
private function getLastColumn($last){ //last represent how mouch X axis spaces
//you want to jump
$max = 26; //Max characters (in number) that you cant jump, ('z´)
$inicial = 'A';
$col = '';
if ($last > $max) //if last is bigger than last you should recall the function
{
$last = $last - $max; //discount the max to the last
$letterAscii = ord($inicial); //tansform the charcter to to number
$letterAscii += ($last - 1); // add last -1(-1 to stay in A to keep the
//base 1)
$col = chr($letterAscii); // int to ascci
$col = $col.$this->getLastColumn($last); // recall the funcion and concat
//the result
}else{
$letterAscii = ord($inicial); // same as adove
$letterAscii += ($last - 1);
$col = chr($letterAscii); //only pass the result to col
}
return $col; //return coll
}
and with this if you need 27 spaces to de right you will get 'AA'
if there is a better solution teld me :)
i think is too late, but for my snippet
i make this function,
function number_to_column($num) {
$column_name = array();
for($i=0;$i<=$num;$i++) {
$numeric = $i % 26;
$letter = chr(65 + $numeric);
$num2 = intval($num / 26);
if ($num2 > 0) {
if($i<26) {
$v_column = $letter;
}
if($i>25 && $i<52) {
$v_column = 'A'.$letter;
}
if($i>51) {
$v_column = 'B'.$letter;
}
$column_name[] = $v_column;
} else {
$v_column = $letter;
$column_name[] = $v_column;
}
}
return $column_name;
}
then we can use it like this
$column_name = number_to_column(count($array[0])-1);
the $column_name will result excel row name,
I'm trying to make a wordsearch game using php. First I will create the table/grid and then populate the table with random letters and then I will replace the random letters with the letters of the words as well as determining the direction of the words either HORIZONTAL, VERTICAL or DIAGONAL. The problem is, the letters of words intersect with each other, which messed up the table. The questions are,
How to set condition where in letters of words will not intersect with each other
How to determine if the current position is already occupied by the other words letter?
I'm having problem with the letters of words they keep intersecting with each other.
Any idea?
$row = 5;
$col = 5;
$characters = range('a','z');
$max = count($characters) - 1;
$rc = array();
for ($r=1;$r<=$row;$r++)
{
for ($c=1;$c<=$col;$c++)
{
$rc['r'.$r.'c'.$c] = $characters[mt_rand(0,$max)];
$fill['r'.$r.'c'.$c] = '';
}
}
$directions = array('H', 'V', 'D');
$wrdList =array('four', 'data', 'howl');
foreach ($wrdList as $wrd)
{
$wrdLen = strlen($wrd);
$dir = $directions[mt_rand(0,2)];
if ($dir =="H" or $dir=="D" )
{
$limitRow = $row - $wrdLen+1;
$limitCol = $col - $wrdLen+1;
$startPointRow = 1;
$startPointCol = 1;
}
elseif ($dir=="V")
{
$limitRow = $row - $wrdLen + 1;
$limitCol = $col;
$startPointRow = 1;
$startPointCol = 1;
}
$temprow = mt_rand($startPointRow,$limitRow);
$tempcol = mt_rand($startPointCol,$limitCol);
while($wrdLen >0)
{
$thisChar= substr($wrd,0,1);
$wrd = substr($wrd,1);
$wrdLen--;
$x = 'r'.$temprow.'c'.$tempcol;
$rc[$x] = $thisChar;
$fill[$x] = '#2952f8';
if($dir=="D")
{
$tempcol++;
$temprow++;
}
elseif($dir=="V")
{
$temprow++;
}
elseif($dir=="H")
{
$tempcol++;
}
}
}
#--Display the random letters and the words
echo '<table style="border:1px solid #000">';
for ($r=1;$r<=$row;$r++)
{
echo '<tr style="border:1px solid #000">';
for ($c=1;$c<=$col;$c++)
{
$thisChar=$rc['r'.$r.'c'.$c];
$fills = $fill['r'.$r.'c'.$c];
echo '<td style="border:1px solid #000; background-color: '.$fills.'">';
echo $thisChar;
echo '</td>';
}
echo '</tr>';
}
echo '</table>';
?>
You're doing it backwards. First put in the words you want, then put in the random letters.
Before you put in each successive word, choose the random path for that word, and then along that path, check that there aren't any non-matching letters. (E.g. if 'alphabet' crosses the word 'graph' in a place where they both have a letter 'a', it's okay; otherwise, find a different spot for 'alphabet'). Finally, after all the words are in place, go through the whole thing and put random letters in the spots that don't have letters. Or, if you can't find a place for all the words, start over again.
EDIT:
How to find letters in particular spots. Okay. So, taking a look at your code, you are doing something illogical here:
$rc['r'.$r.'c'.$c] = $characters[mt_rand(0,$max)];
You are creating a one-dimensional array out of, essentially, the product of two keys. Instead, you want to do a two-dimensional array. This makes complete sense because a) you have two keys, and b) word searches have two dimensions.
$rc[$r][$c] = $characters[mt_rand(0,$max)];
So, let's start at the beginning with everything rearranged. Please note that I have rewritten things to start your row/column count at 0 instead of 1 because that's the programming convention for arrays, and I'm not going to try to bend my brain around counting from 1 just for this.
$wrdList =array('four', 'banana', 'howl');
$row = 5; //six rows counting from 0
$col = 5; //six columns counting from 0
$rc = array(); //our tableau array
$directions = array('H', 'V', 'D');
foreach ($wrdList as $wrd)
{
$found = false; // by default, no spot has been found
$tries = $row*$col; // we will try a reasonable number of times to find a spot
while(!$found && $tries > 0) {
$wrdLen = strlen($wrd);
$dir = $directions[mt_rand(0,2)];
if ($dir =="H")
{
$limitRow = $row;
$limitCol = $col - ($wrdLen - 1);
}
elseif($dir=="D")
{
$limitRow = $row - ($wrdLen - 1);
$limitCol = $col - ($wrdLen - 1);
}
elseif ($dir=="V")
{
$limitRow = $row - ($wrdLen - 1);
$limitCol = $col;
}
$temprow = mt_rand(0,$limitRow);
$tempcol = mt_rand(0,$limitCol);
//this is my temporary placement array
$placement = array();
//let's use for loop so we can capitalize on having numeric keys
$r = $temprow;
$c = $tempcol;
for($w = 0; $w < $wrdLen; $w++) {
$thisChar = $wrd{$w};
//find array keys
if($dir == 'V' || $dir == 'D') {
$r = $temprow + $w;
}
if($dir == 'H' || $dir == 'D') {
$c = $tempcol + $w;
}
//look at the current tableau
if(isset($rc[$r][$c])) { //the intended spot has a letter
if($rc[$r][$c] == $thisChar) { //the intended spot's letter is the same
$placement[$r][$c] = $thisChar;
if($w == $wrdLen-1) { // this is the last letter
$found = true; // we have found a path
}
} else {
break; //this path doesn't work
}
} else {
$placement[$r][$c] = $thisChar;
if($w == $wrdLen-1) { // this is the last letter
$found = true; // we have found a path
}
}
}
if($found) {
//put the letters out of the temporary array and into the tableau
foreach($placement as $r=>$set) {
foreach($set as $c=>$letter) {
$rc[$r][$c] = $letter;
}
}
}
$tries--;
}
//handle the error where no spot was found for the word
if(!$found) {
//your error handling here
}
}
//random fillers
$characters = range('a','z');
$max = count($characters) - 1;
for($r = 0; $r <= $row; $r++) {
for($c = 0; $c <= $col; $c++) {
if(!isset($rc[$r][$c])) {
$rc[$r][$c] = $characters[mt_rand(0,$max)];
}
}
}
I have a container rectangle and element rectangle, both are specified only in height and width. Using PHP I need to figure out what positions and orientation would allow for the most possible blits of the element within the container having absolutely no overlap.
An Example :
$container = array(5000,2000);
$element = array(300,200);
The output should be an array of "blit" arrays (or objects) like so
$blit_object = array($x,$y,$rotation_degrees);
Well, since no one is answering me, I am just going to show my "trial and error" solution in case anyone else ever needs it.
It calculates the two basic layout options and sees which one has the most and uses that.
function MakeBlits($container,$element)
{
$container_x = $container[0];
$container_y = $container[1];
$options = array();
for($i = 0;$i<=1;$i++)
{
if($i == 0)
{
$element_x = $element[0];
$element_y = $element[1];
}
else
{
$element_x = $element[1];
$element_y = $element[0];
}
$test_x = floor($container_x/$element_x);
$test_y = floor($container_y/$element_y);
$test_remainder_x = $container_x - $test_x*$element_x;
$test_remainder_y = $container_y - $test_y*$element_y;
$test_x2 = 0;
$test_x3 = 0;
$test_y2 = 0;
$test_y3 = 0;
if($test_remainder_x > $element_y)
{
$test_x2 = floor($test_remainder_x/$element_y);
$test_y2 = floor($container_y/$element_x);
}
if($test_remainder_y > $element_x)
{
$test_x3 = floor($container_x/$element_y);
$test_y3 = floor($test_remainder_y/$element_x);
}
$options[] = array(
'total'=>($test_x*$test_y)+($test_x2*$test_y2)+($test_x3*$test_y3),
'x'=>$test_x,
'y'=>$test_y,
'x2'=>$test_x2,
'y2'=>$test_y2,
'x3'=>$test_x3,
'y3'=>$test_y3
);
}
if($options[0]['total']>=$options[1]['total'])
{
$option = $options[0];
$rotate = 0;
$width = $element[0];
$height = $element[1];
}
else
{
$option = $options[1];
$rotate = -90;
$width = $element[1];
$height = $element[0];
}
$blit_objects = array();
for($i=0;$i<$option['x'];$i++)
{
for($j=0;$j<$option['y'];$j++)
{
$blit_objects[] = array(
'x'=>$i*$width,
'y'=>$j*$height,
'rotation'=>$rotate);
}
}
for($k = 0;$k < $option['x2'];$k++)
{
for($l = 0;$l < $option['y2'];$l++)
{
$blit_objects[] = array(
'x'=>$i*$width + $k*$height,
'y'=>$l*$width,
'rotation'=>$rotate+90);
}
}
for($k = 0;$k < $option['x3'];$k++)
{
for($l = 0;$l < $option['y3'];$l++)
{
$blit_objects[] = array(
'x'=>$k*$height,
'y'=>$j*$height+$l*$width,
'rotation'=>$rotate+90);
}
}
return $blit_objects;
}
I´m trying to graph a gaussian chart in php. I found the jpgraph library, but I don´t know how to use the $x, $y data. Please somebody who knows how to declare the axis. Thanks. This is my code:
while ($row = pg_fetch_assoc($sql))
{
$ydata = array();
$xdata = array();
$ydata[] = abs(($row['grade']-$miu)/$sigma);
$xdata[] = 0;
for ($i = 0; $i <= 60; $i+=10) // put z value
{
$xdata[] = 0 + $i;
$ydata[] = 0 + $i;
}
$graph = new Graph(600,400,"auto");
$graph->SetScale("linlin");
$lplot = new LinePlot($ydata,$xdata);
$lplot->SetColor("blue");
$lplot->SetWeight(2);
$graph->Add($lplot);
// Add data to X coordinate
$graph->xaxis->SetTickLabels($xdata);
// Display the graph
$graph->Stroke();
}
I already resolved it.
while ($row = pg_fetch_assoc($sql))
{
$z[$i] = ($row['grade'] - $miu)/$sigma; // $z => arreglo con notas normalizadas
$ordenada[$i] = (1/($sigma*sqrt(pi())))*(exp(-0.5*(($row['grade']-$miu)*($row['grade'] - 57))/(12*12)));
$i++;
}
//rest of code
$p1 = new LinePlot($ordenada);
$graph->Add($p1);