Files
ventas_php/classes/comprobante.class.php

1602 lines
46 KiB
PHP
Executable File

<?php
class Comprobante extends Main
{
public $sucursalId;
public function setSucursalId($value)
{
$this->Util()->ValidateInteger($value);
$this->sucursalId = $value;
}
function GenerarComprobante($data, $notaCredito = false)
{
global $empresa;
global $rfc;
global $cliente;
global $util;
global $venta;
$myData = urlencode(serialize($data));
$infEmp = $empresa->InfoAll();
$values = explode("&", $data["datosFacturacion"]);
unset($data["datosFacturacion"]);
foreach($values as $key => $val)
{
$array = explode("=", $values[$key]);
$data[$array[0]] = $array[1];
}
//Datos de la Nota de Venta
$tickets = array();
if($data['ventaId'] != ""){
$ventaId = $data['ventaId'];
$venta->setVentaId($ventaId);
$infV = $venta->Info();
if($infV["status"] == 'Facturada'){
$vs->Util()->setError('', "error", "La nota de venta ya ha sido facturada previamente.");
$vs->Util()->PrintErrors();
return false;
}
}elseif($data['tickets'] != ''){
$tickets = explode('-', $data['tickets']);
//Checar si alguna nota ya se facturo
foreach($tickets as $idVenta){
$venta->setVentaId($idVenta);
$infV = $venta->Info();
if($infV["status"] == 'Facturada'){
$util->setError('', 'error', 'La nota de venta No. '.$infV['folio'].' ya ha sido facturada <br> previamente.');
$util->PrintErrors();
return false;
}
}
}//elseif
$tipoSerie = explode("-", $data["tiposComprobanteId"]);
$data["tiposComprobanteId"] = $tipoSerie[0];
$data["tiposSerieId"] = $tipoSerie[1];
$empresa->setRFC($data["rfc"]);
$empresa->setCalle($data["calle"]);
$empresa->setPais($data["pais"]);
if(strlen($data["formaDePago"]) <= 0)
{
$empresa->Util()->setError(10041, "error", "");
}
if(count($_SESSION["conceptos"]) < 1)
{
$empresa->Util()->setError(10040, "error", "");
}
$myConceptos = urlencode(serialize($_SESSION["conceptos"]));
$myImpuestos = urlencode(serialize($_SESSION["impuestos"]));
$userId = $data["userId"];
$totales = $this->GetTotalDesglosado($data);
/*** AJUSTAMOS TOTALES ***/
$ventaId = $data['ventaId'];
if($ventaId){
$venta->setVentaId($ventaId);
$infV = $venta->Info();
$difCents = $infV['total'] - $totales['total'];
$difCents = number_format($difCents,2,'.','');
if($difCents == 0.01 || $difCents == -0.01){
$totales['iva'] += $difCents;
$totales['ivaThis'] += $difCents;
$totales['total'] += $difCents;
}
$totales['iva'] = number_format($totales['iva'],2,'.','');
$totales['ivaThis'] = number_format($totales['ivaThis'],2,'.','');
}
/*** FIN AJUSTAR TOTALES ***/
if($empresa->Util()->PrintErrors()){ return false; }
if(!$data["tipoDeCambio"])
{
$data["tipoDeCambio"] = "1.00";
}
if(!$data["porcentajeDescuento"])
{
$data["porcentajeDescuento"] = "0";
}
if(!$data["porcentajeIEPS"])
{
$data["porcentajeIEPS"] = "0";
}
//get active rfc
$activeRfc = $rfc->getRfcActive();
//get datos serie de acuerdo al tipo de comprobabte expedido.
if(!$data["metodoDePago"])
{
$empresa->Util()->setError(10047, "error", "El m&eacute;todo de pago no puede ser vac&iacute;o.");
}
if($data["numCtaPago"])
{
if(strlen($data["numCtaPago"]) < 4)
{
$empresa->Util()->setError(10047, "error", "El n&uacute;mero de cuenta debe de tener 4 d&iacute;gitos.");
}
}
if(!$data["tiposComprobanteId"])
{
$empresa->Util()->setError(10047, "error");
}
if($empresa->Util()->PrintErrors()){ return false; }
if($notaCredito)
{
$this->Util()->DBSelect($_SESSION["empresaId"])->setQuery("SELECT * FROM serie WHERE tiposComprobanteId = '2' AND empresaId = ".$_SESSION["empresaId"]." AND rfcId = '".$activeRfc."' AND consecutivo != folioFinal AND serieId = ".$data["tiposSerieId"]." ORDER BY serieId DESC LIMIT 1");
}
else
{
$sql = "SELECT
*
FROM
serie
WHERE
tiposComprobanteId = ".$data["tiposComprobanteId"]."
AND
empresaId = ".$_SESSION["empresaId"]."
AND
rfcId = '".$activeRfc."'
AND
consecutivo != folioFinal
AND
serieId = ".$data["tiposSerieId"]."
ORDER BY
serieId DESC
LIMIT
1";
$this->Util()->DBSelect($_SESSION["empresaId"])->setQuery($sql);
}
$serie = $this->Util()->DBSelect($_SESSION["empresaId"])->GetRow();
if(!$serie)
{
$empresa->Util()->setError(10047, "error");
}
if($empresa->Util()->PrintErrors()){ return false; }
$folio = $serie["consecutivo"];
$fecha = $this->Util()->FormatDateAndTime(time()-600);
//$fecha = "2012-02-07 14:55:52";
//el tipo de comprobante lo determina tiposComprobanteId
$tipoDeComprobante = $this->GetTipoComprobante($data["tiposComprobanteId"]);
$data["comprobante"] = $this->InfoComprobante($data["tiposComprobanteId"]);
$data["serie"] = $serie;
$data["folio"] = $folio;
$data["fecha"] = $fecha;
$data["tipoDeComprobante"] = $tipoDeComprobante;
$data["certificado"] = $serie["noCertificado"];
//Build informacion nodo emisor
$sucursal = new Sucursal;
$sucursal->setSucursalId($data["sucursalId"]);
$nodoEmisor = $sucursal->Info();
$nodoEmisor['identificador'] = $nodoEmisor['nombre'];
$rfc->setRfcId($activeRfc);
$nodoEmisorRfc = $rfc->Info();
$data["nodoEmisor"]["sucursal"] = $nodoEmisor;
$data["nodoEmisor"]["rfc"] = $nodoEmisorRfc;
if(!$data["nodoEmisor"]["rfc"]["regimenFiscal"])
{
$empresa->Util()->setError(10047, "error", "Necesitas el R&eacute;gimen Fiscal. Esto se actualiza en Cat&aacute;logos <br> Mi Empresa, en la opci&oacute;n de edici&oacute;n.");
if($empresa->Util()->PrintErrors()){ return false; }
}
if($_SESSION["version"] == "auto")
{
$rootQr = DOC_ROOT."/empresas/".$_SESSION["empresaId"]."/qrs/";
$qrRfc = strtoupper($nodoEmisorRfc["rfc"]);
$nufa = $serie["serieId"]."_".$serie["noAprobacion"]."_".$qrRfc.".png";
if(!file_exists($rootQr.$nufa))
{
$nufa = $serie["serieId"]."_".$serie["noAprobacion"]."_".$qrRfc."_.png";
if(!file_exists($rootQr.$nufa))
{
$nufa = $serie["serieId"].".png";
if(!file_exists($rootQr.$nufa))
{
$empresa->Util()->setError(10048, "error");
}
}
}
if($empresa->Util()->PrintErrors()){ return false; }
}
$userId = $data["userId"];
//Build informacion Nodo Receptor
if($_SESSION['tipoComp'] == 'Publico'){
$rfc->setRfcId($activeRfc);
$nodoReceptor = $rfc->Info();
$nodoReceptor['nombre'] = $nodoReceptor['razonSocial'];
$data["nodoReceptor"] = $nodoReceptor;
$facturaGlobal = 1;
$fechaIni = $_SESSION['compFI'];
$fechaFin = $_SESSION['compFF'];
}else{
$userId = $data["userId"];
$cliente->setClienteId($userId);
$nodoReceptor = $cliente->Info();
$nodoReceptor = $util->EncodeRow($nodoReceptor);
$data["nodoReceptor"] = $nodoReceptor;
$facturaGlobal = 0;
$fechaIni = '';
$fechaFin = '';
}
//Checar si nos falta unidad en alguno
foreach($_SESSION["conceptos"] as $concepto)
{
if($concepto["unidad"] == "")
{
$empresa->Util()->setError(10048, "error", "El campo de Unidad no puede ser vac&iacute;o.");
}
}
if($empresa->Util()->PrintErrors()){ return false; }
switch($_SESSION["version"])
{
case "auto":
case "v3":
case "construc":
include_once(DOC_ROOT.'/classes/cadena_original_v3.class.php');break;
case "2":
include_once(DOC_ROOT.'/classes/cadena_original_v2.class.php');break;
}
$cadena = new Cadena;
$cadenaOriginal = $cadena->BuildCadenaOriginal($data, $serie, $totales, $nodoEmisor, $nodoReceptor, $_SESSION["conceptos"]);
$data["cadenaOriginal"] = utf8_encode($cadenaOriginal);
$data["cadenaOriginal"] = $cadenaOriginal;
$md5Cadena = utf8_decode($cadenaOriginal);
if(date("Y") > 2010)
{
$md5 = sha1($md5Cadena);
}
$sello = $this->GenerarSello($cadenaOriginal, $md5);
$data["sello"] = $sello["sello"];
$data["certificado"] = $sello["certificado"];
switch($_SESSION["version"])
{
case "auto":
case "v3":
case "construc":
include_once(DOC_ROOT.'/classes/generate_xml_default.class.php');break;
case "2":
include_once(DOC_ROOT.'/classes/generate_xml_v2.class.php');break;
}
$xml = $infEmp["empresaId"]."_".$serie["serie"]."_".$data["folio"];
/*** CHECAR ERROR DE FACTURACION**/
$xmlGen = new XmlGen;
$xml = $xmlGen->GenerateXML($data, $serie, $totales, $nodoEmisor, $nodoReceptor, $_SESSION["conceptos"],$infEmp);
//despues de la generacion del xml, viene el timbrado.
if($_SESSION["version"] == "v3" || $_SESSION["version"] == "construc")
{
$nufa = $infEmp["empresaId"]."_".$serie["serie"]."_".$data["folio"];
$rfcActivo = $rfc->getRfcActive();
$root = DOC_ROOT."/empresas/".$_SESSION["empresaId"]."/certificados/".$rfcActivo."/facturas/xml/";
$root_dos = DOC_ROOT."/empresas/".$_SESSION["empresaId"]."/certificados/".$rfcActivo."/facturas/xml/timbres/";
$nufa_dos = "SIGN_".$infEmp["empresaId"]."_".$serie["serie"]."_".$data["folio"];
$xmlFile = $root.$nufa.".xml";
$zipFile = $root.$nufa.".zip";
$signedFile = $root.$nufa."_signed.zip";
$timbreFile = $root.$nufa."_timbre.zip";
$timbradoFile = $root.$nufa_dos.".xml";
$this->Util()->Zip($root, $nufa);
$user = USER_PAC;
$pw = PW_PAC;
$pac = new Pac;
$response = $pac->GetCfdi($user, $pw, $zipFile, $root, $signedFile, $infEmp["empresaId"]);
$resp = explode('#',$response);
if($resp[0] == "fault")
{
//echo "<b><br><br>Has encontrado un error al Sellar tu Comprobante. Favor de reportarnos este error con todos los detalles posibles. Gracias!!</b>";
$util->setError(20113,'error','Error al Sellar',$resp[1]);
$util->PrintErrors();
return false;
}
$fileTimbreXml = $pac->GetTimbreCfdi($user, $pw, $zipFile, $root, $timbreFile, $infEmp["empresaId"]);
$timbreXml = $pac->ParseTimbre($timbradoFile);
$cadenaOriginalTimbre = $pac->GenerateCadenaOriginalTimbre($timbreXml);
$cadenaOriginalTimbreSerialized = serialize($cadenaOriginalTimbre);
$data["timbreFiscal"] = $cadenaOriginalTimbre;
}
/*
//GeneratePDF
//cambios 29 junio 2011
switch($infEmp["empresaId"])
{
default:
switch($_SESSION["version"])
{
case "v3":
case "construc": include_once(DOC_ROOT."/classes/override_generate_pdf_default.php"); break;
case "auto": include_once(DOC_ROOT."/classes/override_generate_pdf_default_auto.php");break;
case "2": include_once(DOC_ROOT."/classes/override_generate_pdf_default_2.php");break;
}
$override = new Override;
$pdf = $override->GeneratePDF($data, $serie, $totales, $nodoEmisor, $nodoReceptor, $_SESSION["conceptos"],$infEmp);
}
*/
//cambios 29 junio 2011
//insert new comprobante
switch($data["tiposDeMoneda"])
{
case "MXN": $data["tiposDeMoneda"] = "peso"; break;
case "USD": $data["tiposDeMoneda"] = "dolar"; break;
case "EUR": $data["tiposDeMoneda"] = "euro"; break;
}
$this->Util()->DBSelect($_SESSION["empresaId"])->setQuery("
INSERT INTO `comprobante` (
`comprobanteId`,
`userId`,
`formaDePago`,
`condicionesDePago`,
`metodoDePago`,
`tasaIva`,
`tipoDeMoneda`,
`tipoDeCambio`,
`porcentajeRetIva`,
`porcentajeRetIsr`,
`tiposComprobanteId`,
`porcentajeIEPS`,
`porcentajeDescuento`,
`empresaId`,
`sucursalId`,
`observaciones`,
`serie`,
`folio`,
`fecha`,
`sello`,
`noAprobacion`,
`anoAprobacion`,
`noCertificado`,
`certificado`,
`subtotal`,
`descuento`,
`motivoDescuento`,
`total`,
`tipoDeComprobante`,
`xml`,
`rfcId`,
`ivaTotal`,
`data`,
`conceptos`,
`impuestos`,
`cadenaOriginal`,
`timbreFiscal`,
`facturaGlobal`,
`fechaIni`,
`fechaFin`
) VALUES
(
NULL,
'".$userId."',
'".$data["formaDePago"]."',
'".$data["condicionesDePago"]."',
'".$data["metodoDePago"]."',
'".$data["tasaIva"]."',
'".$data["tiposDeMoneda"]."',
'".$data["tipoDeCambio"]."',
'".$data["porcentajeRetIva"]."',
'".$data["porcentajeRetIsr"]."',
'".$data["tiposComprobanteId"]."',
'".$data["porcentajeIEPS"]."',
'".$data["porcentajeDescuento"]."',
'".$infEmp["empresaId"]."',
'".$data["sucursalId"]."',
'".$data["observaciones"]."',
'".$serie["serie"]."',
'".$folio."',
'".$fecha."',
'".$data["sello"]."',
'".$serie["noAprobacion"]."',
'".$serie["anoAprobacion"]."',
'".$serie["noCertificado"]."',
'".$data["certificado"]."',
'".$totales["subtotal"]."',
'".$totales["descuento"]."',
'".$data["motivoDescuento"]."',
'".$totales["total"]."',
'".$tipoDeComprobante."',
'".$xml."',
'".$data["nodoEmisor"]["rfc"]["rfcId"]."',
'".$totales["iva"]."',
'".$myData."',
'".$myConceptos."',
'".$myImpuestos."',
'".htmlspecialchars($data["cadenaOriginal"], ENT_QUOTES)."',
'".$cadenaOriginalTimbreSerialized."',
'".$facturaGlobal."',
'".$fechaIni."',
'".$fechaFin."'
)");
$this->Util()->DBSelect($_SESSION["empresaId"])->InsertData();
$this->Util()->DBSelect($_SESSION["empresaId"])->setQuery("SELECT comprobanteId FROM comprobante ORDER BY comprobanteId DESC LIMIT 1");
$comprobanteId = $this->Util()->DBSelect($_SESSION["empresaId"])->GetSingle();
if($data['ventaId'] != ""){
$sql = "UPDATE
venta
SET
comprobanteId = '".$comprobanteId."',
status = 'Facturada'
WHERE
ventaId = '".$data["ventaId"]."'";
$this->Util()->DBSelect($_SESSION["empresaId"])->setQuery($sql);
$this->Util()->DBSelect($_SESSION["empresaId"])->UpdateData();
}elseif(count($tickets) > 0){
//Actualizamos los tickets a facturado
foreach($tickets as $ventaId){
$sql = "UPDATE venta
SET comprobanteId = '".$comprobanteId."',
status = 'Facturada'
WHERE
ventaId = '".$ventaId."'";
$this->Util()->DBSelect($_SESSION["empresaId"])->setQuery($sql);
$this->Util()->DBSelect($_SESSION["empresaId"])->UpdateData();
}
}//elseif
//Insert Conceptos
foreach($_SESSION["conceptos"] as $concepto)
{
$this->Util()->DBSelect($_SESSION["empresaId"])->setQuery("
INSERT INTO `concepto` (
`comprobanteId`,
`cantidad`,
`unidad`,
`noIdentificacion`,
`descripcion`,
`valorUnitario`,
`excentoIva`,
`importe`,
`userId`,
`empresaId`
) VALUES (
".$comprobanteId.",
".$concepto["cantidad"].",
'".$concepto["unidad"]."',
'".htmlspecialchars($concepto["noIdentificacion"], ENT_QUOTES)."',
'".htmlspecialchars($concepto["descripcion"], ENT_QUOTES)."',
".$concepto["valorUnitario"].",
'".$concepto["excentoIva"]."',
".$concepto["importe"].",
'".$userId."',
".$infEmp["empresaId"]."
)");
$this->Util()->DBSelect($_SESSION["empresaId"])->InsertData();
}//foreach
unset($_SESSION["notasPorFacturar"]);
unset($_SESSION["conceptos"]);
//Finally we update the consecutivo
$this->Util()->DBSelect($_SESSION["empresaId"])->setQuery("UPDATE serie SET consecutivo = consecutivo + 1 WHERE serieId = ".$serie["serieId"]);
$this->Util()->DBSelect($_SESSION["empresaId"])->UpdateData();
return true;
}//GenerarComprobante
function CancelarComprobante($data, $comprobanteId, $notaCredito = false, $recipient)
{
global $rfc;
$sql = "SELECT noCertificado, xml, rfc FROM comprobante
LEFT JOIN cliente ON cliente.clienteId = comprobante.userId
WHERE comprobanteId = ".$comprobanteId;
$this->Util()->DBSelect($_SESSION["empresaId"])->setQuery($sql);
$row = $this->Util()->DBSelect($_SESSION["empresaId"])->GetRow();
$xml = $row["xml"];
$info = $this->GetInfoComprobante($comprobanteId);
/*
if($info["version"] == "v3" || $info["version"] == "construc")
{
$rfcActivo = $rfc->getRfcActive();
$root = DOC_ROOT."/empresas/".$_SESSION["empresaId"]."/certificados/".$rfcActivo."/facturas/xml/SIGN_".$xml.".xml";
$fh = fopen($root, 'r');
$theData = fread($fh, filesize($root));
fclose($fh);
$theData = explode("UUID", $theData);
$theData = $theData[1];
$theData = explode("FechaTimbrado", $theData);
$theData = $theData[0];
$uuid = str_replace("\"", "", $theData);
$uuid = str_replace("=", "", $uuid);
$uuid = str_replace(" ", "", $uuid);
$path = DOC_ROOT."/empresas/".$_SESSION["empresaId"]."/certificados/".$rfcActivo."/".$row["noCertificado"].".cer.pfx";
$user = USER_PAC;
$pw = PW_PAC;
$pac = new Pac;
//get password
$root = DOC_ROOT."/empresas/".$_SESSION["empresaId"]."/certificados/".$rfcActivo."/password.txt";
$fh = fopen($root, 'r');
$password = fread($fh, filesize($root));
fclose($fh);
if(!$password)
{
$this->Util()->setError('', "error", "Tienes que actualizar tu certificado para que podamos obtener el password");
$this->Util()->PrintErrors();
return false;
}
$rfc->setRfcId($rfcActivo);
$nodoEmisorRfc = $rfc->InfoRfc();
$response = $pac->CancelaCfdi($user, $pw, $nodoEmisorRfc["rfc"], $uuid, $path, $password);
}
*/
$this->Util()->DBSelect($_SESSION["empresaId"])->setQuery("UPDATE comprobante SET status = '0' WHERE comprobanteId = ".$comprobanteId);
$this->Util()->DBSelect($_SESSION["empresaId"])->UpdateData();
$fileName = $xml.".pdf";
$path = DOC_ROOT."/empresas/".$_SESSION["empresaId"]."/certificados/1/facturas/pdf/".$fileName;
//$pdf =& new FPDI();
$pdf = new FPDI();
$pagecount = $pdf->setSourceFile($path);
$tplidx = $pdf->importPage(1, '/MediaBox');
$pdf->addPage();
$pdf->useTemplate($tplidx, 0, 0, 210);
$pdf->AddFont('verdana','','verdana.php');
$pdf->SetFont('verdana','',72);
$pdf->SetY(100);
$pdf->SetX(10);
$pdf->SetTextColor(200, 0, 0);
$pdf->Cell(20,10,"CANCELADO",0,0,'L');
$pdf->Output($path, 'F');
$this->Util()->setError('', "complete", "El folio ha sido cancelado correctamente.");
$this->Util()->PrintErrors();
return true;
}//CancelarComprobante
function GetTotalDesglosado($data)
{
if(!$_SESSION["conceptos"])
{
return false;
}
$data["subtotal"] = 0;
$data["descuento"] = 0;
$data["iva"] = 0;
$data["ieps"] = 0;
$data["retIva"] = 0;
$data["retIsr"] = 0;
$data["total"] = 0;
foreach($data as $key => $value)
{
$data[$key] = $this->Util()->RoundNumber($data[$key]);
}
foreach($_SESSION["conceptos"] as $key => $concepto)
{
//cada concepto correrle los impuestos extra.
if($_SESSION["impuestos"])
{
$importe = $concepto["importe"];
foreach($_SESSION["impuestos"] as $keyImpuesto => $impuesto)
{
// print_r($impuesto);
//impuesto extra, suma
if($_SESSION["impuestos"][$keyImpuesto]["importe"] != 0)
{
// echo $_SESSION["impuestos"][$keyImpuesto]["importe"];
if($impuesto["tipo"] == "impuesto")
{
$concepto["importe"] = $concepto["importe"] + $_SESSION["impuestos"][$keyImpuesto]["importe"];
}
elseif($impuesto["tipo"] == "retencion")
{
$concepto["importe"] = $concepto["importe"] - $_SESSION["impuestos"][$keyImpuesto]["importe"];
}
elseif($impuesto["tipo"] == "deduccion")
{
$concepto["importe"] = $concepto["importe"] - $_SESSION["impuestos"][$keyImpuesto]["importe"];
}
elseif($impuesto["tipo"] == "amortizacion")
{
$concepto["importe"] = $concepto["importe"] - $_SESSION["impuestos"][$keyImpuesto]["importe"];
}
continue;
}
if($impuesto["tipo"] == "impuesto")
{
$concepto["importe"] = $concepto["importe"] + ($importe * ($impuesto["tasa"] / 100));
$_SESSION["impuestos"][$keyImpuesto]["importe"] = $importe * ($impuesto["tasa"] / 100);
}
elseif($impuesto["tipo"] == "retencion")
{
$concepto["importe"] = $concepto["importe"] - ($importe * ($impuesto["tasa"] / 100));
$_SESSION["impuestos"][$keyImpuesto]["importe"] = $importe * ($impuesto["tasa"] / 100);
}
elseif($impuesto["tipo"] == "deduccion")
{
$concepto["importe"] = $concepto["importe"] - ($importe * ($impuesto["tasa"] / 100));
$_SESSION["impuestos"][$keyImpuesto]["importe"] = $importe * ($impuesto["tasa"] / 100);
}
}//foreach
}//impuestos
$data["subtotal"] = $this->Util()->RoundNumber($data["subtotal"] + $concepto["importe"]);
if($concepto["excentoIva"] == "si")
{
$_SESSION["conceptos"][$key]["tasaIva"] = 0;
}
else
{
$_SESSION["conceptos"][$key]["tasaIva"] = $data["tasaIva"];
}
//porcentaje de descuento
if($data["porcentajeDescuento"])
{
$data["porcentajeDescuento"];
}
$data["descuentoThis"] = $this->Util()->RoundNumber($_SESSION["conceptos"][$key]["importe"] * ($data["porcentajeDescuento"] / 100));
$data["descuento"] += $data["descuentoThis"];
$afterDescuento = $_SESSION["conceptos"][$key]["importe"] - $data["descuentoThis"];
if($concepto["excentoIva"] == "si")
{
$_SESSION["conceptos"][$key]["tasaIva"] = 0;
}
else
{
$_SESSION["conceptos"][$key]["tasaIva"] = $data["tasaIva"];
}
$data["ivaThis"] = $this->Util()->RoundNumber($afterDescuento * ($_SESSION["conceptos"][$key]["tasaIva"] / 100));
$data["iva"] += $data["ivaThis"];
$data["valorUnitario"] = $concepto["valorUnitario"];
$concepto["importe"] = $importe;
}
$afterDescuento = $data["subtotal"] - $data["descuento"];
//ieps de descuento
if(!$data["porcentajeIEPS"])
{
$data["porcentajeIEPS"] = 0;
}
$data["ieps"] = $this->Util()->RoundNumber($afterDescuento * ($data["porcentajeIEPS"] / 100));
$afterImpuestos = $afterDescuento + $data["iva"] + $data["ieps"];
$data["retIva"] = $this->Util()->RoundNumber($afterDescuento * ($data["porcentajeRetIva"] / 100));
$data["retIsr"] = $this->Util()->RoundNumber($afterDescuento * ($data["porcentajeRetIsr"] / 100));
$data["total"] = $this->Util()->RoundNumber($data["subtotal"] - $data["descuento"] + $data["iva"] + $data["ieps"] - $data["retIva"] - $data["retIsr"]);
return $data;
}
protected function GetTipoComprobante($value)
{
$this->Util()->DBSelect($_SESSION["empresaId"])->setQuery("SELECT tipoDeComprobante FROM tiposComprobante WHERE tiposComprobanteId = ".$value." LIMIT 1");
return $this->Util()->DBSelect($_SESSION["empresaId"])->GetSingle();
}
function GenerarSello($cadenaOriginal, $md5)
{
global $rfc;
$root = DOC_ROOT."/empresas/".$_SESSION["empresaId"]."/certificados/";
if(!is_dir($root))
{
mkdir($root, 0777);
}
$data["certificado"] = $arr['noCertificado'];
$rfcActivo = $rfc->getRfcActive();
$root = DOC_ROOT."/empresas/".$_SESSION["empresaId"]."/certificados/".$rfcActivo."/";
if(!is_dir($root))
{
mkdir($root, 0777);
}
if ($handle = opendir($root))
{
while (false !== ($file = readdir($handle)))
{
$ext = substr($file, -7);
if($ext == "cer.pem")
{
$cert = $file;
}
if($ext == "key.pem")
{
$key = $file;
}
}
}
closedir($handle);
$file=$root.$key; // Ruta al archivo
//write md5 to txt
$fp = fopen ($root."/md5.txt", "w+");
fwrite($fp, $md5);
fclose($fp);
//sign the original md5 with private key
exec("openssl dgst -sha1 -sign ".$file." -out ".$root."/md5sha1.txt ".$root."/md5.txt");
$myFile = $root."/md5sha1.txt";
$fh = fopen($myFile, 'r');
$theData = fread($fh, filesize($myFile));
fclose($fh);
//generate public
exec("openssl rsa -in ".$file." -pubout -out ".$root."/publickey.txt");
//verify
exec("openssl dgst -sha1 -verify ".$root."/publickey.txt -out ".$root."/verified.txt -signature ".$root."/md5sha1.txt ".$root."/md5.txt");
$cadenaOriginalDecoded = utf8_decode($cadenaOriginal);
$file = $root.$cert; // Ruta al archivo
$datos = file($file);
$data["certificado"] = "";
$carga=false;
for ($i=0; $i<sizeof($datos); $i++)
{
if (strstr($datos[$i],"END CERTIFICATE")) $carga=false;
if ($carga)
{
$data["certificado"] .= trim($datos[$i]);
}
if (strstr($datos[$i],"BEGIN CERTIFICATE")) $carga=true;
}
$keyFile = $root.$key;
$pkeyid = openssl_get_privatekey(file_get_contents($root.$key));
// openssl_sign($cadenaOriginal, $crypttext, $pkeyid, OPENSSL_ALGO_SHA1);
openssl_sign($cadenaOriginalDecoded, $crypttext, $pkeyid, OPENSSL_ALGO_SHA1);
$data["sello"] = base64_encode($crypttext);
return $data;
}
function GenerarSelloGral($cadenaOriginal, $md5, $certificado, $llave, $pass, $id_rfc)
{
$id_empresa = $_SESSION['empresaId'];
$file = DOC_ROOT.'/empresas/'.$id_empresa.'/certificados/'.$id_rfc.'/'.$certificado.'.pem'; // Ruta al archivo
$root = DOC_ROOT.'/empresas/'.$id_empresa.'/certificados/'.$id_rfc;
//write md5 to txt
$fp = fopen ($root."/md5.txt", "w+");
fwrite($fp, $md5);
fclose($fp);
//generate .key.pem file
exec('openssl pkcs8 -inform DER -in '.$root.'/'.$certificado.' -out '.$root.'/'.$certificado.'.pem -passin pass:'.$pass);
//generate .cer.pem file
exec('openssl x509 -inform DER -outform PEM -in '.$root.'/'.$llave.' -out '.$root.'/'.$llave.'.pem');
//sign the original md5 with private key
exec("openssl dgst -sha1 -sign ".$file." -out ".$root."/md5sha1.txt ".$root."/md5.txt");
//generate public
exec("openssl rsa -in ".$file." -pubout -out ".$root."/publickey.txt");
//verify
exec("openssl dgst -sha1 -verify ".$root."/publickey.txt -out ".$root."/verified.txt -signature ".$root."/md5sha1.txt ".$root."/md5.txt");
//changed 02 agosto
//generate merge
exec('openssl pkcs12 -export -out '.$root.'/'.$llave.'.pfx -inkey '.$root.'/'.$certificado.'.pem -in '.$root.'/'.$llave.'.pem -passout pass:'.$pass);
//changed 02 agosto
}//GenerarSelloGral
function GetLastComprobante()
{
$this->Util()->DBSelect($_SESSION["empresaId"])->setQuery("SELECT * FROM comprobante ORDER BY comprobanteId DESC");
$row = $this->Util()->DBSelect($_SESSION["empresaId"])->GetRow();
$row["path"] = urlencode(DOC_ROOT."/empresas/".$row["empresaId"]."/certificados/".$row["rfcId"]."/facturas/");
return $row;
}
function GetInfoComprobante($comprobanteId){
$sqlQuery = 'SELECT * FROM comprobante WHERE comprobanteId = "'.$comprobanteId.'"';
$this->Util()->DBSelect($_SESSION["empresaId"])->setQuery($sqlQuery);
$row = $this->Util()->DBSelect($_SESSION["empresaId"])->GetRow();
return $row;
}//GetInfoComprobante
function GetComprobantesBySuc(){
global $rfc;
global $user;
$rfcId = $rfc->getRfcActive();
$sql = 'SELECT COUNT(*) FROM comprobante
WHERE rfcId = "'.$rfcId.'"
AND sucursalId = "'.$this->sucursalId.'"
AND facturaGlobal = "0"
ORDER BY fecha DESC';
$this->Util()->DBSelect($_SESSION["empresaId"])->setQuery($sql);
$total = $this->Util()->DBSelect($_SESSION["empresaId"])->GetSingle();
$pages = $this->Util->HandleMultipages($this->page, $total ,WEB_ROOT."/facturacion");
$sqlAdd = "LIMIT ".$pages["start"].", ".$pages["items_per_page"];
$sql = 'SELECT * FROM comprobante
WHERE rfcId = "'.$rfcId.'"
AND sucursalId = "'.$this->sucursalId.'"
AND facturaGlobal = "0"
ORDER BY fecha DESC '.$sqlAdd;
$this->Util()->DBSelect($_SESSION['empresaId'])->setQuery($sql);
$comprobantes = $this->Util()->DBSelect($_SESSION['empresaId'])->GetResult();
$data["items"] = $comprobantes;
$data["pages"] = $pages;
return $data;
}//GetComprobantesBySuc
function GetCompMensBySuc(){
global $rfc;
global $user;
$rfcId = $rfc->getRfcActive();
$sql = 'SELECT COUNT(*) FROM comprobante
WHERE rfcId = "'.$rfcId.'"
AND sucursalId = "'.$this->sucursalId.'"
AND facturaGlobal = "1"
ORDER BY fecha DESC';
$this->Util()->DBSelect($_SESSION["empresaId"])->setQuery($sql);
$total = $this->Util()->DBSelect($_SESSION["empresaId"])->GetSingle();
$pages = $this->Util->HandleMultipages($this->page, $total ,WEB_ROOT."/facturacion");
$sqlAdd = "LIMIT ".$pages["start"].", ".$pages["items_per_page"];
$sql = 'SELECT * FROM comprobante
WHERE rfcId = "'.$rfcId.'"
AND sucursalId = "'.$this->sucursalId.'"
AND facturaGlobal = "1"
ORDER BY fecha DESC '.$sqlAdd;
$this->Util()->DBSelect($_SESSION['empresaId'])->setQuery($sql);
$comprobantes = $this->Util()->DBSelect($_SESSION['empresaId'])->GetResult();
$data["items"] = $comprobantes;
$data["pages"] = $pages;
return $data;
}//GetCompMensBySuc
function SearchComprobantesByRfc($values){
global $user;
$sqlSearch = '';
if($values['rfc']){
$sqlSearch .= ' AND u.rfc LIKE "%'.$values['rfc'].'%"';
}//if
if($values['nombre']){
$sqlSearch .= ' AND u.nombre LIKE "%'.$values['nombre'].'%"';
}//if
if($values['mes']){
$sqlSearch .= ' AND EXTRACT(MONTH FROM c.fecha) = '.$values['mes'];
}//if
if($values['anio'])
$sqlSearch .= ' AND EXTRACT(YEAR FROM c.fecha) = '.intval($values['anio']);
if($values['status_activo'] != '')
$sqlSearch .= ' AND c.status = "'.$values['status_activo'].'"';
if($values['comprobante'])
$sqlSearch .= ' AND c.tiposComprobanteId = '.$values['comprobante'];
if($values['sucursal'])
$sqlSearch .= ' AND c.sucursalId = '.$values['sucursal'];
$id_rfc = $this->getRfcActive();
$sqlQuery = 'SELECT
c.*
FROM
comprobante AS c,
cliente AS u
WHERE
c.userId = u.userId
AND c.rfcId = '.$id_rfc.$sqlSearch.'
ORDER BY
c.fecha DESC';
$id_empresa = $_SESSION['empresaId'];
$this->Util()->DBSelect($id_empresa)->setQuery($sqlQuery);
$comprobantes = $this->Util()->DBSelect($id_empresa)->GetResult();
$info = array();
foreach($comprobantes as $key => $val){
$user->setUserId($val['userId'],1);
$usr = $user->GetUserInfo();
$card['serie'] = $val['serie'];
$card['folio'] = $val['folio'];
$card['rfc'] = $usr['rfc'];
$card['nombre'] = $usr['nombre'];
$card['fecha'] = date('d/m/Y',strtotime($val['fecha']));
$card['subTotal'] = $val['subTotal'];
$card['porcentajeDescuento'] = $val['porcentajeDescuento'];
$card['descuento'] = $val['descuento'];
$card['ivaTotal'] = $val['ivaTotal'];
$card['total'] = $val['total'];
$card['total_formato'] = number_format($val['total'],2,'.',',');
$card['tipoDeMoneda'] = $val['tipoDeMoneda'];
$card['tipoDeCambio'] = $val['tipoDeCambio'];
$card['porcentajeRetIva'] = $val['porcentajeRetIva'];
$card['porcentajeRetIsr'] = $val['porcentajeRetIsr'];
$card['porcentajeIEPS'] = $val['porcentajeIEPS'];
$card['comprobanteId'] = $val['comprobanteId'];
$card['status'] = $val['status'];
$card['tickets'] = $this->GetRangeTicketsByComp($val['comprobanteId']);
$info[$key] = $card;
}//foreach
$data["items"] = $info;
$data["pages"] = $pages;
return $data;
}//SearchComprobantesByRfc
function GenerateQR($data, $totales, $nodoEmisor, $nodoReceptor, $empresa, $serie)
{
global $rfc;
$total = $this->Util()->RoundNumber($totales["total"], 6);
$total = $this->Util()->PadStringLeft(number_format($total, 6, ".", ""), 14, "0");
$cadenaCodigoBarras = "?re=".$data["nodoEmisor"]["rfc"]["rfc"]."&rr=".$nodoReceptor["rfc"]."&tt=".$total."&id=".$data["timbreFiscal"]["UUID"];
$nufa = $empresa["empresaId"]."_".$serie["serie"]."_".$data["folio"];
$rfcActivo = $rfc->getRfcActive();
$root = DOC_ROOT."/empresas/".$_SESSION["empresaId"]."/certificados/".$rfcActivo."/facturas/qr/";
$rootFacturas = DOC_ROOT."/empresas/".$_SESSION["empresaId"]."/certificados/".$rfcActivo."/facturas/";
if(!is_dir($rootFacturas))
{
mkdir($rootFacturas, 0777);
}
if(!is_dir($root))
{
mkdir($root, 0777);
}
//$pdf->Output($root.$nufa.".pdf", "F");
QRcode::png($cadenaCodigoBarras, $root.$nufa.".png", 'L', 4, 2);
}
}//Comprobante
require(DOC_ROOT.'/pdf/fpdf.php');
require(DOC_ROOT.'/pdf/fpdi.php');
class PDF extends FPDF
{
var $widths;
var $aligns;
//Page header
function Header()
{
//Logo
//Arial bold 15
$this->SetFont('Arial','B',10);
$this->SetY(0);
$this->SetX(0);
$this->Cell(70,10,'http://novomoda.ddns.net',0,0,'C');
//Line break
$this->Ln(20);
}
//Page footer
function Footer()
{
//Position at 1.5 cm from bottom
$this->SetY(-8);
//Arial italic 8
$this->SetFont('Arial','I',8);
//Page number
$this->Cell(0,10,$this->PageNo().'/{nb}',0,0,'C');
}
function RoundedRect($x, $y, $w, $h, $r, $style = '', $angle = '1234')
{
$k = $this->k;
$hp = $this->h;
if($style=='F')
$op='f';
elseif($style=='FD' or $style=='DF')
$op='B';
else
$op='S';
$MyArc = 4/3 * (sqrt(2) - 1);
$this->_out(sprintf('%.2f %.2f m', ($x+$r)*$k, ($hp-$y)*$k ));
$xc = $x+$w-$r;
$yc = $y+$r;
$this->_out(sprintf('%.2f %.2f l', $xc*$k, ($hp-$y)*$k ));
if (strpos($angle, '2')===false)
$this->_out(sprintf('%.2f %.2f l', ($x+$w)*$k, ($hp-$y)*$k ));
else
$this->_Arc($xc + $r*$MyArc, $yc - $r, $xc + $r, $yc - $r*$MyArc, $xc + $r, $yc);
$xc = $x+$w-$r;
$yc = $y+$h-$r;
$this->_out(sprintf('%.2f %.2f l', ($x+$w)*$k, ($hp-$yc)*$k));
if (strpos($angle, '3')===false)
$this->_out(sprintf('%.2f %.2f l', ($x+$w)*$k, ($hp-($y+$h))*$k));
else
$this->_Arc($xc + $r, $yc + $r*$MyArc, $xc + $r*$MyArc, $yc + $r, $xc, $yc + $r);
$xc = $x+$r;
$yc = $y+$h-$r;
$this->_out(sprintf('%.2f %.2f l', $xc*$k, ($hp-($y+$h))*$k));
if (strpos($angle, '4')===false)
$this->_out(sprintf('%.2f %.2f l', ($x)*$k, ($hp-($y+$h))*$k));
else
$this->_Arc($xc - $r*$MyArc, $yc + $r, $xc - $r, $yc + $r*$MyArc, $xc - $r, $yc);
$xc = $x+$r ;
$yc = $y+$r;
$this->_out(sprintf('%.2f %.2f l', ($x)*$k, ($hp-$yc)*$k ));
if (strpos($angle, '1')===false)
{
$this->_out(sprintf('%.2f %.2f l', ($x)*$k, ($hp-$y)*$k ));
$this->_out(sprintf('%.2f %.2f l', ($x+$r)*$k, ($hp-$y)*$k ));
}
else
$this->_Arc($xc - $r, $yc - $r*$MyArc, $xc - $r*$MyArc, $yc - $r, $xc, $yc - $r);
$this->_out($op);
}
function _Arc($x1, $y1, $x2, $y2, $x3, $y3)
{
$h = $this->h;
$this->_out(sprintf('%.2f %.2f %.2f %.2f %.2f %.2f c ', $x1*$this->k, ($h-$y1)*$this->k,
$x2*$this->k, ($h-$y2)*$this->k, $x3*$this->k, ($h-$y3)*$this->k));
}
function WordWrap(&$text, $maxwidth)
{
$text = trim($text);
if ($text==='')
return 0;
$space = $this->GetStringWidth(' ');
$lines = explode("\n", $text);
$text = '';
$count = 0;
foreach ($lines as $line)
{
$words = preg_split('/ +/', $line);
$width = 0;
foreach ($words as $word)
{
$wordwidth = $this->GetStringWidth($word);
if ($width + $wordwidth <= $maxwidth)
{
$width += $wordwidth + $space;
$text .= $word.' ';
}
else
{
$width = $wordwidth + $space;
$text = rtrim($text)."\n".$word.' ';
$count++;
}
}
$text = rtrim($text)."\n";
$count++;
}
$text = rtrim($text);
return $count;
}
function SetWidths($w)
{
//Set the array of column widths
$this->widths=$w;
}
function SetAligns($a)
{
//Set the array of column alignments
$this->aligns=$a;
}
function Row($data, $pixelHeight = 5)
{
//Calculate the height of the row
$nb=0;
for($i=0;$i<count($data);$i++)
$nb=max($nb, $this->NbLines($this->widths[$i], $data[$i]));
$h=$pixelHeight * $nb;
//Issue a page break first if needed
$this->CheckPageBreak($h);
//Draw the cells of the row
for($i=0;$i<count($data);$i++)
{
$w=$this->widths[$i];
$a=isset($this->aligns[$i]) ? $this->aligns[$i] : 'L';
// print_r($a);
//Save the current position
$x=$this->GetX();
$y=$this->GetY();
//Draw the border
//$this->Rect($x, $y, $w, $h);
//Print the text
$this->MultiCell($w, $pixelHeight, $data[$i], 0, $a);
//Put the position to the right of the cell
$this->SetXY($x+$w, $y);
}
//Go to the next line
$this->Ln($h);
}
function CheckPageBreak($h)
{
//If the height h would cause an overflow, add a new page immediately
if($this->GetY()+$h>$this->PageBreakTrigger)
$this->AddPage($this->CurOrientation);
}
function NbLines($w, $txt)
{
//Computes the number of lines a MultiCell of width w will take
$cw=&$this->CurrentFont['cw'];
if($w==0)
$w=$this->w-$this->rMargin-$this->x;
$wmax=($w-2*$this->cMargin)*1000/$this->FontSize;
$s=str_replace("\r", '', $txt);
$nb=strlen($s);
if($nb>0 and $s[$nb-1]=="\n")
$nb--;
$sep=-1;
$i=0;
$j=0;
$l=0;
$nl=1;
while($i<$nb)
{
$c=$s[$i];
if($c=="\n")
{
$i++;
$sep=-1;
$j=$i;
$l=0;
$nl++;
continue;
}
if($c==' ')
$sep=$i;
$l+=$cw[$c];
if($l>$wmax)
{
if($sep==-1)
{
if($i==$j)
$i++;
}
else
$i=$sep+1;
$sep=-1;
$j=$i;
$l=0;
$nl++;
}
else
$i++;
}
return $nl;
}
}
class PDF_ImageAlpha extends PDF{
//Private properties
var $tmpFiles = array();
/*******************************************************************************
* *
* Public methods *
* *
*******************************************************************************/
function ImageX($file,$x,$y,$w=0,$h=0,$type='',$link='', $isMask=false, $maskImg=0)
{
//Put an image on the page
if(!isset($this->images[$file]))
{
//First use of image, get info
if($type=='')
{
$pos=strrpos($file,'.');
if(!$pos)
$this->Error('Image file has no extension and no type was specified: '.$file);
$type=substr($file,$pos+1);
}
$type=strtolower($type);
$mqr=@get_magic_quotes_runtime();
@set_magic_quotes_runtime(0);
if($type=='jpg' || $type=='jpeg')
$info=$this->_parsejpg($file);
elseif($type=='png'){
$info=$this->_parsepng($file);
if ($info=='alpha') return $this->ImagePngWithAlpha($file,$x,$y,$w,$h,$link);
}
else
{
//Allow for additional formats
$mtd='_parse'.$type;
if(!method_exists($this,$mtd))
$this->Error('Unsupported image type: '.$type);
$info=$this->$mtd($file);
}
@set_magic_quotes_runtime($mqr);
if ($isMask){
$info['cs']="DeviceGray"; // try to force grayscale (instead of indexed)
}
$info['i']=count($this->images)+1;
if ($maskImg>0) $info['masked'] = $maskImg;###
$this->images[$file]=$info;
}
else
$info=$this->images[$file];
//Automatic width and height calculation if needed
if($w==0 && $h==0)
{
//Put image at 72 dpi
$w=$info['w']/$this->k;
$h=$info['h']/$this->k;
}
if($w==0)
$w=$h*$info['w']/$info['h'];
if($h==0)
$h=$w*$info['h']/$info['w'];
if ($isMask) $x = ($this->CurOrientation=='P'?$this->CurPageFormat[0]:$this->CurPageFormat[1]) + 10; // embed hidden, ouside the canvas
$this->_out(sprintf('q %.2f 0 0 %.2f %.2f %.2f cm /I%d Do Q',$w*$this->k,$h*$this->k,$x*$this->k,($this->h-($y+$h))*$this->k,$info['i']));
if($link)
$this->Link($x,$y,$w,$h,$link);
return $info['i'];
}
// needs GD 2.x extension
// pixel-wise operation, not very fast
function ImagePngWithAlpha($file,$x,$y,$w=0,$h=0,$link='')
{
$tmp_alpha = tempnam('.', 'mska');
$this->tmpFiles[] = $tmp_alpha;
$tmp_plain = tempnam('.', 'mskp');
$this->tmpFiles[] = $tmp_plain;
list($wpx, $hpx) = getimagesize($file);
$img = imagecreatefrompng($file);
$alpha_img = imagecreate( $wpx, $hpx );
// generate gray scale pallete
for($c=0;$c<256;$c++) ImageColorAllocate($alpha_img, $c, $c, $c);
// extract alpha channel
$xpx=0;
while ($xpx<$wpx){
$ypx = 0;
while ($ypx<$hpx){
$color_index = imagecolorat($img, $xpx, $ypx);
$alpha = 255-($color_index>>24)*255/127; // GD alpha component: 7 bit only, 0..127!
imagesetpixel($alpha_img, $xpx, $ypx, $alpha);
++$ypx;
}
++$xpx;
}
imagepng($alpha_img, $tmp_alpha);
imagedestroy($alpha_img);
// extract image without alpha channel
$plain_img = imagecreatetruecolor ( $wpx, $hpx );
imagecopy ($plain_img, $img, 0, 0, 0, 0, $wpx, $hpx );
imagepng($plain_img, $tmp_plain);
imagedestroy($plain_img);
//first embed mask image (w, h, x, will be ignored)
$maskImg = $this->ImageX($tmp_alpha, 0,0,0,0, 'PNG', '', true);
//embed image, masked with previously embedded mask
$this->ImageX($tmp_plain,$x,$y,$w,$h,'PNG',$link, false, $maskImg);
}
function Close()
{
parent::Close();
// clean up tmp files
foreach($this->tmpFiles as $tmp) @unlink($tmp);
}
/*******************************************************************************
* *
* Private methods *
* *
*******************************************************************************/
function _putimages()
{
$filter=($this->compress) ? '/Filter /FlateDecode ' : '';
reset($this->images);
foreach($this->images as $file => $info)
{
$this->_newobj();
$this->images[$file]['n']=$this->n;
$this->_out('<</Type /XObject');
$this->_out('/Subtype /Image');
$this->_out('/Width '.$info['w']);
$this->_out('/Height '.$info['h']);
if (isset($info["masked"])) $this->_out('/SMask '.($this->n-1).' 0 R'); ###
if($info['cs']=='Indexed')
$this->_out('/ColorSpace [/Indexed /DeviceRGB '.(strlen($info['pal'])/3-1).' '.($this->n+1).' 0 R]');
else
{
$this->_out('/ColorSpace /'.$info['cs']);
if($info['cs']=='DeviceCMYK')
$this->_out('/Decode [1 0 1 0 1 0 1 0]');
}
$this->_out('/BitsPerComponent '.$info['bpc']);
if(isset($info['f']))
$this->_out('/Filter /'.$info['f']);
if(isset($info['parms']))
$this->_out($info['parms']);
if(isset($info['trns']) && is_array($info['trns']))
{
$trns='';
for($i=0;$i<count($info['trns']);$i++)
$trns.=$info['trns'][$i].' '.$info['trns'][$i].' ';
$this->_out('/Mask ['.$trns.']');
}
$this->_out('/Length '.strlen($info['data']).'>>');
$this->_putstream($info['data']);
unset($this->images[$file]['data']);
$this->_out('endobj');
//Palette
if($info['cs']=='Indexed')
{
$this->_newobj();
$pal=($this->compress) ? gzcompress($info['pal']) : $info['pal'];
$this->_out('<<'.$filter.'/Length '.strlen($pal).'>>');
$this->_putstream($pal);
$this->_out('endobj');
}
}
}
// this method overwriing the original version is only needed to make the Image method support PNGs with alpha channels.
// if you only use the ImagePngWithAlpha method for such PNGs, you can remove it from this script.
function _parsepng($file)
{
//Extract info from a PNG file
$f=fopen($file,'rb');
if(!$f)
$this->Error('Can\'t open image file: '.$file);
//Check signature
if(fread($f,8)!=chr(137).'PNG'.chr(13).chr(10).chr(26).chr(10))
$this->Error('Not a PNG file: '.$file);
//Read header chunk
fread($f,4);
if(fread($f,4)!='IHDR')
$this->Error('Incorrect PNG file: '.$file);
$w=$this->_readint($f);
$h=$this->_readint($f);
$bpc=ord(fread($f,1));
if($bpc>8)
$this->Error('16-bit depth not supported: '.$file);
$ct=ord(fread($f,1));
if($ct==0)
$colspace='DeviceGray';
elseif($ct==2)
$colspace='DeviceRGB';
elseif($ct==3)
$colspace='Indexed';
else {
fclose($f); // the only changes are
return 'alpha'; // made in those 2 lines
}
if(ord(fread($f,1))!=0)
$this->Error('Unknown compression method: '.$file);
if(ord(fread($f,1))!=0)
$this->Error('Unknown filter method: '.$file);
if(ord(fread($f,1))!=0)
$this->Error('Interlacing not supported: '.$file);
fread($f,4);
$parms='/DecodeParms <</Predictor 15 /Colors '.($ct==2 ? 3 : 1).' /BitsPerComponent '.$bpc.' /Columns '.$w.'>>';
//Scan chunks looking for palette, transparency and image data
$pal='';
$trns='';
$data='';
do
{
$n=$this->_readint($f);
$type=fread($f,4);
if($type=='PLTE')
{
//Read palette
$pal=fread($f,$n);
fread($f,4);
}
elseif($type=='tRNS')
{
//Read transparency info
$t=fread($f,$n);
if($ct==0)
$trns=array(ord(substr($t,1,1)));
elseif($ct==2)
$trns=array(ord(substr($t,1,1)),ord(substr($t,3,1)),ord(substr($t,5,1)));
else
{
$pos=strpos($t,chr(0));
if($pos!==false)
$trns=array($pos);
}
fread($f,4);
}
elseif($type=='IDAT')
{
//Read image data block
$data.=fread($f,$n);
fread($f,4);
}
elseif($type=='IEND')
break;
else
fread($f,$n+4);
}
while($n);
if($colspace=='Indexed' && empty($pal))
$this->Error('Missing palette in '.$file);
fclose($f);
return array('w'=>$w,'h'=>$h,'cs'=>$colspace,'bpc'=>$bpc,'f'=>'FlateDecode','parms'=>$parms,'pal'=>$pal,'trns'=>$trns,'data'=>$data);
}
}
?>