Initial commit

This commit is contained in:
Ben Ramey
2017-03-02 20:30:40 -06:00
commit ab3c6fc8d5
10773 changed files with 515124 additions and 0 deletions

110
production/classes/cache/cache.php vendored Normal file
View File

@@ -0,0 +1,110 @@
<?php
/*
+--------------------------------------------------------------------------
| CubeCart 4
| ========================================
| CubeCart is a registered trade mark of Devellion Limited
| Copyright Devellion Limited 2006. All rights reserved.
| Devellion Limited,
| 5 Bridge Street,
| Bishops Stortford,
| HERTFORDSHIRE.
| CM23 2JU
| UNITED KINGDOM
| http://www.devellion.com
| UK Private Limited Company No. 5323904
| ========================================
| Web: http://www.cubecart.com
| Email: info (at) cubecart (dot) com
| License Type: CubeCart is NOT Open Source Software and Limitations Apply
| Licence Info: http://www.cubecart.com/site/faq/license.php
+--------------------------------------------------------------------------
| cache.php
| ========================================
| Cache Class to Save MySQL Processes
+--------------------------------------------------------------------------
*/
class cache {
var $filename;
var $out;
var $cacheStatus = false;
var $identifier;
function cache($identifier = null) {
if (!$this->enabled()) return false;
if (!cc_is_wriatble(CC_ROOT_DIR.CC_DS."cache")) die("<strong>Error: ".CC_DS."cache folder is not writable!</strong> This can be made writable by accessing your store files with an FTP client or via your web hosting control panel if it has a file manager. The cache folder requires a file permission of 0777 (or as high as your hosting company allows e.g. 0775)");
$this->identifier = $identifier;
$this->filename .= CC_ROOT_DIR.CC_DS."cache".CC_DS;
$this->readCache(false);
}
function enabled() {
global $config;
return ($config['cache']) ? true : false;
}
function writeCache($dataIn) {
if (!$this->enabled()) return false;
$this->filename .= $this->path();
$this->out = serialize($dataIn);
return $this->write();
}
function clearCache() {
if (!$this->enabled()) return false;
if (!empty($this->identifier)) {
$filename = $this->filename.$this->path();
@unlink($filename);
#########################
} else {
foreach(glob($this->filename."*.php") as $filename) {
@unlink($filename);
}
}
}
function path() {
if (!$this->enabled()) return false;
return $this->identifier.".inc.php";
}
function write() {
if (!$this->enabled()) return false;
if (strlen($this->out)>0) {
if (!$handle = fopen($this->filename, 'w')) {
$error = true;
}
if (fwrite($handle, $this->out) === false) {
$error = TRUE;
}
fclose($handle);
if ($error) {
die("Cache not writable! Please disable cache functionality or make it writable.");
} else {
return true;
}
}
}
function readCache($return = true) {
if (!$this->enabled()) return false;
$cacheFile = $this->filename.$this->path();
if (!@file_exists($cacheFile)) {
return false;
} else {
$this->cacheStatus = true;
}
if ($return == true) {
$fileConts = file_get_contents($cacheFile);
$data = unserialize($fileConts);
return (!empty($data)) ? $data : false;
}
}
}
?>

View File

@@ -0,0 +1,78 @@
<?php
/*
+--------------------------------------------------------------------------
| CubeCart 4
| ========================================
| CubeCart is a registered trade mark of Devellion Limited
| Copyright Devellion Limited 2006. All rights reserved.
| Devellion Limited,
| 5 Bridge Street,
| Bishops Stortford,
| HERTFORDSHIRE.
| CM23 2JU
| UNITED KINGDOM
| http://www.devellion.com
| UK Private Limited Company No. 5323904
| ========================================
| Web: http://www.cubecart.com
| Email: info (at) cubecart (dot) com
| License Type: CubeCart is NOT Open Source Software and Limitations Apply
| Licence Info: http://www.cubecart.com/site/faq/license.php
+--------------------------------------------------------------------------
| encrypt.inc.php
| ========================================
| Class Encrypts Data
+--------------------------------------------------------------------------
*/
class encryption {
var $td;
var $iv;
var $ks;
var $key;
##############################################
function __construct($keyArray = null) {
$this->encryption($keyArray);
}
function encryption($keyArray = null) {
$this->td = mcrypt_module_open(MCRYPT_RIJNDAEL_256, '', 'ecb', '');
$this->iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($this->td), MCRYPT_RAND);
$this->ks = mcrypt_enc_get_key_size($this->td);
if (!is_null($keyArray) && is_array($keyArray)) $this->generateKey($keyArray);
}
##############################################
function __destruct() {
$this->close();
}
function close() {
@mcrypt_module_close($this->td);
}
##############################################
function generateKey($keyArray) {
$this->key = substr(md5(implode('@', $keyArray)), 0, $this->ks);
}
function encrypt($data) {
mcrypt_generic_init($this->td, $this->key, $this->iv);
$stringEncrypted = mcrypt_generic($this->td, $data);
mcrypt_generic_deinit($this->td);
return $stringEncrypted;
}
function decrypt($stringEncrypted) {
if (!empty($stringEncrypted)) {
mcrypt_generic_init($this->td, $this->key, $this->iv);
$stringDecrypted = mdecrypt_generic($this->td, $stringEncrypted);
mcrypt_generic_deinit($this->td);
return trim($stringDecrypted);
}
}
}
?>

View File

@@ -0,0 +1,692 @@
<?php
/*
+--------------------------------------------------------------------------
| CubeCart 4
| ========================================
| CubeCart is a registered trade mark of Devellion Limited
| Copyright Devellion Limited 2006. All rights reserved.
| Devellion Limited,
| 5 Bridge Street,
| Bishops Stortford,
| HERTFORDSHIRE.
| CM23 2JU
| UNITED KINGDOM
| http://www.devellion.com
| UK Private Limited Company No. 5323904
| ========================================
| Web: http://www.cubecart.com
| Email: info (at) cubecart (dot) com
| License Type: CubeCart is NOT Open Source Software and Limitations Apply
| Licence Info: http://www.cubecart.com/site/faq/license.php
+--------------------------------------------------------------------------
| order.php
| ========================================
| Core Order Class
+--------------------------------------------------------------------------
*/
class order {
var $order;
var $orderSum;
var $orderInv;
/*
function order() {
## Process level constants
define('ORDER_PENDING', 1);
define('ORDER_PROCESSING', 2);
define('ORDER_COMPLETE', 3);
define('ORDER_DECLINED', 4);
define('ORDER_FAILED', 5);
define('ORDER_CANCELLED', 6);
}
*/
function storeTrans($transData, $forceLog = true) {
global $glob, $db;
$transDataSQL['time'] = $db->MySQLSafe(time());
$transDataSQL['customer_id'] = $db->MySQLSafe($transData['customer_id']);
$transDataSQL['gateway'] = $db->MySQLSafe($transData['gateway']);
$transDataSQL['extra'] = $db->MySQLSafe($transData['extra']);
$transDataSQL['trans_id'] = $db->MySQLSafe($transData['trans_id']);
$transDataSQL['order_id'] = $db->MySQLSafe($transData['order_id']);
$transDataSQL['status'] = $db->MySQLSafe($transData['status']);
$transDataSQL['amount'] = $db->MySQLSafe($transData['amount']);
$transDataSQL['notes'] = $db->MySQLSafe($transData['notes']);
// make sure status isn't repeated on last call
$maxStatus = $db->select("SELECT max(`id`), `status` FROM ".$glob['dbprefix']."CubeCart_transactions WHERE `trans_id` = ".$transDataSQL['trans_id']." GROUP BY `id` DESC");
if (!$forceLog && ($maxStatus[0]['status'] !== $transData['status'] || !$maxStatus)) {
$db->insert($glob['dbprefix']."CubeCart_transactions", $transDataSQL);
} else if ($forceLog) {
$db->insert($glob['dbprefix']."CubeCart_transactions", $transDataSQL);
}
}
function mkOrderNo() {
$this->cart_order_id = date("ymd-His-").rand(1000, 9999);
return $this->cart_order_id;
}
function getOrderSum($cart_order_id) {
global $db, $glob;
$query = "SELECT * FROM ".$glob['dbprefix']."CubeCart_order_sum INNER JOIN ".$glob['dbprefix']."CubeCart_customer ON ".$glob['dbprefix']."CubeCart_order_sum.customer_id = ".$glob['dbprefix']."CubeCart_customer.customer_id WHERE ".$glob['dbprefix']."CubeCart_order_sum.cart_order_id = ".$db->mySQLSafe($cart_order_id);
$order = $db->select($query);
$this->orderSum = $order[0];
return $order[0];
}
function getOrderInv($cart_order_id) {
global $db, $glob;
$products = $db->select("SELECT * FROM ".$glob['dbprefix']."CubeCart_order_inv WHERE cart_order_id = ".$db->mySQLSafe($cart_order_id));
$this->orderInv = $products;
return $this->orderInv;
}
function deleteOrder($cart_order_id) {
global $db, $glob;
$where = "cart_order_id = '".$cart_order_id."'";
$delete = $db->delete($glob['dbprefix']."CubeCart_order_sum", $where);
$delete = $db->delete($glob['dbprefix']."CubeCart_order_inv", $where);
$delete = $db->delete($glob['dbprefix']."CubeCart_Downloads", $where);
}
function customerOrderCount($customerId, $value) {
global $db, $glob;
$record['noOrders'] = ($value>0) ? "noOrders + ".$value : "noOrders - ".$value;
$where = "customer_id = ".$customerId;
$update = $db->update($glob['dbprefix']."CubeCart_customer", $record, $where);
}
function manageStock($statusId,$cart_order_id){
global $db, $glob, $config;
if(!is_array($this->orderInv)){
$this->getOrderInv($cart_order_id);
}
for($i=0; $i<count($this->orderInv); $i++) {
// see if product uses stock or not
$useStock = $db->select("SELECT useStockLevel FROM ".$glob['dbprefix']."CubeCart_inventory WHERE productId = ".$db->mySQLSafe($this->orderInv[$i]['productId']));
// if it does continue
if ($useStock[0]['useStockLevel']) {
// reduce stock on payment recieved
if (!$config['stock_change_time']) {
$reduceStockStatus = 3;
} else if ($config['stock_change_time'] == 1) {
$reduceStockStatus = 2;
} elseif($config['stock_change_time'] == 2) {
$reduceStockStatus = 1;
// override possible config error cant put stock back for pending orders in this state
$config['stock_replace_time'][1] = 0;
}
// reduce stock if not already and status matches time to reduce stock
if($this->orderInv[$i]['stockUpdated']==0 && $statusId == $reduceStockStatus) {
$this->stockLevel($this->orderInv[$i]['quantity'], "-", $this->orderInv[$i]['productId'], $this->orderInv[$i]['id'], 1);
// replace stock if reduced already and status permits
} elseif($this->orderInv[$i]['stockUpdated']==1 && $config['stock_replace_time'][$statusId]==1) {
$this->stockLevel($this->orderInv[$i]['quantity'], "+", $this->orderInv[$i]['productId'], $this->orderInv[$i]['id'], 0);
}
}
}
}
function orderStatus($statusId, $cart_order_id, $force = false, $skipEmail = false) {
global $db, $glob, $config;
/*
1. Pending (New Order)
2. Processing (See order notes)
3. Order Complete & Dispatched
4. Declined (See notes)
5. Failed Fraud Review
6. Cancelled
*/
// First make sure this process isn't being repeated! Some payment processors
// send more than once in the XML if other attributes have changed
$currentStatus = $db->select("SELECT `status` FROM ".$glob['dbprefix']."CubeCart_order_sum WHERE `cart_order_id` = ".$db->MySQLSafe($cart_order_id) );
$this->manageStock($statusId, $cart_order_id);
if ($currentStatus[0]['status'] !== $statusId) {
switch($statusId) {
case 2; ## Processing Nothing to do
## Email the customer to say payment has been accepted and cleared
$lang = getLang("email.inc.php");
$this->getOrderSum($cart_order_id);
$macroArray = array(
"ORDER_ID" => $this->orderSum['cart_order_id'],
"RECIP_NAME" => $this->orderSum['name'],
"STORE_URL" => $glob['storeURL']
);
$text = macroSub($lang['email']['payment_complete_body'], $macroArray);
unset($macroArray);
## Send email
require_once CC_ROOT_DIR.CC_DS."classes".CC_DS."htmlMimeMail".CC_DS."htmlMimeMail.php";
$mail = new htmlMimeMail();
$mail->setText($text);
$mail->setReturnPath($this->orderSum['email']);
$mail->setFrom($config['masterName'].' <'.$config['masterEmail'].'>');
$mail->setSubject(macroSub($lang['email']['payment_complete_subject'], array("ORDER_ID" => $this->orderSum['cart_order_id'])));
$mail->setHeader('X-Mailer', 'CubeCart Mailer');
$mail->setBcc($config['masterEmail']);
$mail->send(array($this->orderSum['email']), $config['mailMethod']);
break;
case 3: ## Order Complete (Payment Taken/Cleared)
$breakStatus = false;
## Look up order
$this->getOrderSum($cart_order_id);
$this->getOrderInv($cart_order_id);
# $count = count($this->orderInv);
# for ($i=0; $i<$count; $i++) {
if (is_array($this->orderInv)) {
foreach ($this->orderInv as $i => $orderItem) {
## If the order contains tangible items, we set it to ORDER_PROCESSING, and break the loop
if (!$this->orderInv[$i]['digital'] && !$force) {
$this->orderStatus(2, $cart_order_id);
$statusId = 2; ## Safeguard
$breakStatus = true; ## Stops email sending below no way to stop this case ?!
break;
}
## Send Gift Certificate
if (!empty($this->orderInv[$i]['custom'])) {
$customArray = unserialize($this->orderInv[$i]['custom']);
if ($customArray['cert'] == true) {
$this->sendCoupon($customArray, $this->orderInv[$i]['id']);
}
}
}
if($breakStatus == false) {
## If order is completely digital send digital file and keep status as complete
$this->digitalAccess();
## Send order complete email OOOOOH it's a bit diiiirty
$lang = getLang("email.inc.php");
if ($this->orderSum['discount']>0) {
$grandTotal = priceFormat($this->orderSum['prod_total'], true)." (-".priceFormat($this->orderSum['discount'], true).")";
} else {
$grandTotal = priceFormat($this->orderSum['prod_total'], true);
}
$macroArray = array(
"RECIP_NAME" => $this->orderSum['name'],
"ORDER_ID" => $this->orderSum['cart_order_id'],
"ORDER_DATE" => formatTime($this->orderSum['time']),
"INVOICE_NAME" => $this->orderSum['name'],
"SUBTOTAL" => priceFormat($this->orderSum['subtotal'], true),
"SHIPPING_COST" => priceFormat($this->orderSum['total_ship'], true),
"TAX_COST" => priceFormat($this->orderSum['total_tax'], true),
"GRAND_TOTAL" => $grandTotal,
"INVOICE_ADD_1" => $this->orderSum['add_1'],
"INVOICE_ADD_2" => $this->orderSum['add_2'],
"INVOICE_CITY" => $this->orderSum['town'],
"INVOICE_REGION" => $this->orderSum['county'],
"INVOICE_POSTCODE" => $this->orderSum['postcode'],
"INVOICE_COUNTRY" => getCountryFormat($this->orderSum['country'], 'id', 'printable_name'),
"DELIVERY_NAME" => $this->orderSum['name_d'],
"DELIVERY_ADD_1" => $this->orderSum['add_1_d'],
"DELIVERY_ADD_2" => $this->orderSum['add_2_d'],
"DELIVERY_CITY" => $this->orderSum['town_d'],
"DELIVERY_REGION" => $this->orderSum['county_d'],
"DELIVERY_POSTCODE" => $this->orderSum['postcode_d'],
"DELIVERY_COUNTRY" => $this->orderSum['country_d'],
"PAYMENT_METHOD" => $this->orderSum['gateway'],
"DELIVERY_METHOD" => $this->orderSum['shipMethod']
);
$text = macroSub($lang['email']['order_breakdown_1'],$macroArray);
unset($macroArray);
if(!empty($this->orderSum['customer_comments'])) {
$macroArray = array(
"CUSTOMER_COMMENTS" => $this->orderSum['customer_comments']
);
$text .= macroSub($lang['email']['order_breakdown_2'],$macroArray);
unset($macroArray);
}
$text .= $lang['email']['order_breakdown_3'];
for ($i=0; $i<count($this->orderInv); $i++) {
$macroArray = array(
"PRODUCT_NAME" => $this->orderInv[$i]['name']
);
$text .= macroSub($lang['email']['order_breakdown_4'],$macroArray);
unset($macroArray);
$macroArray = array(
"PRODUCT_OPTIONS" => $this->orderInv[$i]['product_options']
);
$text .= macroSub($lang['email']['order_breakdown_5'],$macroArray);
unset($macroArray);
$macroArray = array(
"PRODUCT_QUANTITY" => $this->orderInv[$i]['quantity'],
"PRODUCT_CODE" => $this->orderInv[$i]['productCode'],
"PRODUCT_PRICE" => priceFormat($this->orderInv[$i]['price'],true)
);
$text .= macroSub($lang['email']['order_breakdown_6'],$macroArray);
unset($macroArray);
}
# //$lang['email']['order_breakdown_7'] => "EXTRA_NOTES", coments to customer to do
## Send email
require_once CC_ROOT_DIR.CC_DS."classes".CC_DS."htmlMimeMail".CC_DS."htmlMimeMail.php";
$mail = new htmlMimeMail();
$mail->setText($text);
$mail->setReturnPath($this->orderSum['email']);
$mail->setFrom($config['masterName'].' <'.$config['masterEmail'].'>');
$mail->setSubject(macroSub($lang['email']['order_breakdown_subject'], array("ORDER_ID" => $this->orderSum['cart_order_id'])));
$mail->setHeader('X-Mailer', 'CubeCart Mailer');
$mail->setBcc($config['masterEmail']);
$mail->send(array($this->orderSum['email']), $config['mailMethod']);
}
}
break;
//case 4: // Declined nothing to do
//break;
case 5:
## email customer to explain their order failed fraud review
$this->orderSum = $this->getOrderSum($cart_order_id);
$lang = getLang("email.inc.php");
$macroArray = array(
"ORDER_ID" => $this->orderSum['cart_order_id'],
"RECIP_NAME" => $this->orderSum['name'],
"ORDER_URL_PATH" => $glob['storeURL']."/index.php?_g=co&_a=viewOrder&cart_order_id=".$this->orderSum['cart_order_id'],
"STORE_URL" => $glob['storeURL']
);
$text = macroSub($lang['email']['fraud_body'],$macroArray);
unset($macroArray);
## send email
require_once CC_ROOT_DIR.CC_DS."classes".CC_DS."htmlMimeMail".CC_DS."htmlMimeMail.php";
$mail = new htmlMimeMail();
$mail->setText($text);
$mail->setReturnPath($this->orderSum['email']);
$mail->setFrom($config['masterName'].' <'.$config['masterEmail'].'>');
$mail->setSubject(macroSub($lang['email']['fraud_subject'],array("ORDER_ID" => $this->orderSum['cart_order_id'])));
$mail->setHeader('X-Mailer', 'CubeCart Mailer');
$mail->setBcc($config['masterEmail']);
$mail->send(array($this->orderSum['email']), $config['mailMethod']);
break;
case 6: ## cancelled (Can be cancelled by either admin/customer)
$this->orderSum = $this->getOrderSum($cart_order_id);
if (!$skipEmail) {
$lang = getLang("email.inc.php");
$macroArray = array(
"ORDER_ID" => $this->orderSum['cart_order_id'],
"RECIP_NAME" => $this->orderSum['name'],
"ORDER_URL_PATH" => $glob['storeURL']."/index.php?_g=co&_a=viewOrder&cart_order_id=".$this->orderSum['cart_order_id'],
"STORE_URL" => $glob['storeURL']
);
$text = macroSub($lang['email']['payment_cancelled_body'],$macroArray);
unset($macroArray);
## Send email
require_once CC_ROOT_DIR.CC_DS."classes".CC_DS."htmlMimeMail".CC_DS."htmlMimeMail.php";
$mail = new htmlMimeMail();
$mail->setText($text);
$mail->setReturnPath($this->orderSum['email']);
$mail->setFrom($config['masterName'].' <'.$config['masterEmail'].'>');
$mail->setSubject(macroSub($lang['email']['payment_cancelled_subject'],array("ORDER_ID" => $this->orderSum['cart_order_id'])));
$mail->setHeader('X-Mailer', 'CubeCart Mailer');
$mail->setBcc($config['masterEmail']);
$mail->send(array($this->orderSum['email']), $config['mailMethod']);
break;
}
}
$data['status'] = $statusId;
$db->update($glob['dbprefix']."CubeCart_order_sum", $data, "cart_order_id=".$db->mySQLSafe($cart_order_id));
return true;
}
return false;
}
function stockLevel($level, $sign, $productId, $orderInvId, $stockUpdated) {
global $db, $glob;
$query = "UPDATE ".$glob['dbprefix']."CubeCart_inventory SET stock_level = stock_level ".$sign." ".$level." WHERE `productId` = ".$productId;
$update = $db->misc($query);
$query = "UPDATE ".$glob['dbprefix']."CubeCart_order_inv SET stockUpdated = ".$stockUpdated." WHERE `id` = ".$orderInvId;
$update = $db->misc($query);
}
function sendCoupon($customArray, $id) {
global $db, $cart_order_id, $glob, $lang, $config, $order;
## Create coupon code for the gift certificate
$chars = array("A","B","C","D","E","F","G","H","J","K","L",'M',"N","P","Q","R","S","T","U","V","W","X","Y","Z");
$max_chars = count($chars)-1;
$coupon = sprintf('%s-%d-%d', $chars[mt_rand(0, $max_chars)].$chars[mt_rand(0, $max_chars)], time(), mt_rand(1000, 9999));
## e.g: RW-1147691506-6723
$data['status'] = $db->mySQLSafe(1);
$data['code'] = $db->mySQLSafe($coupon);
$data['discount_percent'] = $db->mySQLSafe(0);
$data['discount_price'] = $db->mySQLSafe($customArray['amount']);
$data['expires'] = $db->mySQLSafe(date('m/d/').(date('Y')+2));
$data['allowed_uses'] = $db->mySQLSafe(0);
$data['cart_order_id'] = $db->mySQLSafe($this->orderSum['cart_order_id']);
$db->insert($glob['dbprefix']."CubeCart_Coupons", $data);
$couponId['couponId'] = $db->insertid();
$db->update($glob['dbprefix'].'CubeCart_order_inv', $couponId, 'id='.$db->mySQLSafe($id));
$lang = getLang('email.inc.php');
$macroArray = array(
"RECIP_NAME" => $customArray['recipName'],
"SENDER_NAME" => $this->orderSum['name'],
"SENDER_EMAIL" => $this->orderSum['email'],
"AMOUNT" => priceFormat($customArray['amount'], true),
"MESSAGE" => $customArray['message'],
"COUPON" => $coupon,
"STORE_URL" => $glob['storeURL']
);
$couponText = macroSub($lang['email']['coupon_body'], $macroArray);
unset($macroArray);
## Send email
require_once CC_ROOT_DIR.CC_DS."classes".CC_DS."htmlMimeMail".CC_DS."htmlMimeMail.php";
$mail = new htmlMimeMail();
$mail->setText($couponText);
$mail->setReturnPath($customArray['recipEmail']);
$mail->setFrom($config['masterName'].' <'.$config['masterEmail'].'>');
$mail->setSubject($lang['email']['coupon_subject']);
$mail->setHeader('X-Mailer', 'CubeCart Mailer');
$mail->send(array($customArray['recipEmail']), $config['mailMethod']);
}
function digitalAccess() {
global $db, $glob, $lang, $config;
$digitalProducts = $db->select("SELECT * FROM ".$glob['dbprefix']."CubeCart_Downloads INNER JOIN ".$glob['dbprefix']."CubeCart_inventory ON ".$glob['dbprefix']."CubeCart_Downloads.productId = ".$glob['dbprefix']."CubeCart_inventory.productId WHERE cart_order_id = ".$db->mySQLSafe($this->orderSum['cart_order_id']));
if($digitalProducts == true) {
require_once CC_ROOT_DIR.CC_DS."classes".CC_DS."htmlMimeMail".CC_DS."htmlMimeMail.php";
$lang = getLang("email.inc.php");
$mail = new htmlMimeMail();
## build email with access details
$macroArray = array(
"RECIP_NAME" => $this->orderSum['name'],
"ORDER_ID" => $this->orderSum['cart_order_id'],
"ORDER_DATE" => formatTime($this->orderSum['time']),
"EXPIRE_DATE" => formatTime($digitalProducts[0]['expire']),
"DOWNLOAD_ATTEMPTS" => $config['dnLoadTimes'],
);
$text = macroSub($lang['email']['downloads_body'],$macroArray);
unset($macroArray);
for($i=0; $i<count($digitalProducts); $i++) {
$macroArray = array(
"PRODUCT_NAME" => $digitalProducts[$i]['name'],
"DOWNLOAD_URL" => $glob['storeURL']."/index.php?_g=dl&pid=".$digitalProducts[$i]['productId']."&oid=".base64_encode($this->orderSum['cart_order_id'])."&ak=".$digitalProducts[$i]['accessKey']
);
$text .= macroSub($lang['email']['downloads_body_2'], $macroArray);
unset($macroArray);
}
$mail->setText($text);
$mail->setReturnPath($this->orderSum['email']);
$mail->setFrom($config['masterName'].' <'.$config['masterEmail'].'>');
$macroArray = array("ORDER_ID" => $this->orderSum['cart_order_id']);
$mail->setSubject(macroSub($lang['email']['downloads_subject'],$macroArray));
$mail->setHeader('X-Mailer', 'CubeCart Mailer');
$mail->send(array($this->orderSum['email']), $config['mailMethod']);
}
}
function cancelOldOrders() {
global $db, $glob, $config;
if($config['orderExpire']==0) {
return false;
} else {
$expiryLimit = time() - $config['orderExpire'];
$expiredOrders = $db->select("SELECT `cart_order_id` FROM ".$glob['dbprefix']."CubeCart_order_sum WHERE `status` = 1 AND `time` < ".$expiryLimit);
if($expiredOrders) {
for($i=0; $i<count($expiredOrders); $i++) {
$this->orderStatus(6, $expiredOrders[$i]['cart_order_id']);
}
}
return true;
}
}
function createOrder($orderInv, $orderSum, $skipEmail = false) {
global $glob, $config, $db;
/*
Repeated Order Inventory Variables
$orderInv[$i]['productId']
$orderInv[$i]['name']
$orderInv[$i]['price']
$orderInv[$i]['quantity']
$orderInv[$i]['product_options']
$orderInv[$i]['productCode']
$orderInv[$i]['digital']
$orderInv[$i]['custom']
Order Summary Variables
$orderSum['cart_order_id']
$orderSum['customer_id']
$orderSum['email']
$orderSum['name']
$orderSum['add_1']
$orderSum['add_2']
$orderSum['town']
$orderSum['county']
$orderSum['postcode']
$orderSum['country']
$orderSum['phone']
$orderSum['mobile']
$orderSum['currency']
$orderSum['name_d']
$orderSum['add_1_d']
$orderSum['add_2_d']
$orderSum['town_d']
$orderSum['county_d']
$orderSum['postcode_d']
$orderSum['country_d']
$orderSum['subtotal']
$orderSum['discount']
$orderSum['total_ship']
$orderSum['total_tax']
$orderSum['prod_total']
$orderSum['shipMethod']
$orderSum['tax'.$i.'_disp'] = $taxes[$i]['display'];
$orderSum['tax'.$i.'_amt'] = $taxes[$i]['amount'];
$orderSum['gateway']
$orderSum['basket']
*/
if (is_array($orderInv)) {
for ($i=1; $i<=count($orderInv); $i++) {
foreach ($orderInv[$i] as $key => $value) {
$orderInvIn[$key] = $db->mySQLSafe($value);
$orderInvIn['cart_order_id'] = $db->mySQLSafe($orderSum['cart_order_id']);
}
$insert = $db->insert($glob['dbprefix']."CubeCart_order_inv", $orderInvIn);
/*
$useStock = $db->select("SELECT useStockLevel FROM ". $glob['dbprefix'] . "CubeCart_inventory WHERE productId = ".$db->mySQLSafe($orderInv[$i]['productId']));
// lower stock level IF it is set to change on order creation
if($useStock[0]['useStockLevel']==1 && $config['stock_change_time']==2) {
$this->stockLevel($orderInv[$i]['quantity'],$orderInv[$i]['productId'],$orderSum['cart_order_id']);
}
*/
if ($orderInv[$i]['digital'] == true) {
$digitalProduct['cart_order_id'] = $db->mySQLSafe($orderSum['cart_order_id']);
$digitalProduct['customerId'] = $db->mySQLSafe($orderSum['customer_id']);
$digitalProduct['expire'] = $db->mySQLSafe(time()+$config['dnLoadExpire']);
$digitalProduct['productId'] = $db->mySQLSafe($orderInv[$i]['productId']);
$digitalProduct['accessKey'] = $db->mySQLSafe(randomPass());
$insert = $db->insert($glob['dbprefix']."CubeCart_Downloads", $digitalProduct);
}
}
if (!$insert) {
echo "An error building the order inventory was encountered. Please inform a member of staff.";
exit;
}
}
## Insert order summary
if (is_array($orderSum)) {
foreach ($orderSum as $key => $value) {
$orderSumIn[$key] = $db->mySQLSafe($value);
}
$orderSumIn['ip'] = $db->mySQLSafe(get_ip_address());
$orderSumIn['time'] = $db->mySQLSafe(time());
$db->insert($glob['dbprefix']."CubeCart_order_sum", $orderSumIn);
}
## update customers order count + 1
$this->customerOrderCount($orderSum['customer_id'], 1);
$this->orderSum = $orderSum;
if($skipEmail==false) {
$this->newOrderEmail();
}
## set order status to 1, this will reduce stock accordingly
$this->orderStatus(1, $orderSum['cart_order_id']);
$this->cancelOldOrders();
}
function newOrderEmail($cart_order_id = '') {
global $glob, $config, $lang;
if (!empty($cart_order_id)) {
$this->getOrderSum($cart_order_id);
$this->getOrderInv($cart_order_id);
}
if (!class_exists('htmlMimeMail')) {
require_once CC_ROOT_DIR.CC_DS."classes".CC_DS."htmlMimeMail".CC_DS."htmlMimeMail.php";
}
$lang = getLang("email.inc.php");
## email to storekeeper
if ($config['disable_alert_email'] != true) {
$mail = new htmlMimeMail();
$macroArray = array(
"CUSTOMER_NAME" => $this->orderSum['name'],
"ORDER_ID" => $this->orderSum['cart_order_id'],
"ADMIN_ORDER_URL" => $glob['storeURL']."/".$glob['adminFile']."?_g=orders/orderBuilder&edit=".$this->orderSum['cart_order_id'],
"SENDER_ID" => get_ip_address(),
);
$text = macroSub($lang['email']['admin_pending_order_body'],$macroArray);
unset($macroArray);
$mail->setText($text);
$mail->setReturnPath($config['masterEmail']);
$mail->setFrom($this->orderSum['name'].' <'.$this->orderSum['email'].'>');
$mail->setSubject(macroSub($lang['email']['admin_pending_order_subject'],array("ORDER_ID" => $this->orderSum['cart_order_id'])));
$mail->setHeader('X-Mailer', 'CubeCart Mailer');
$mail->send(array($config['masterEmail']), $config['mailMethod']);
}
## email to customer
$mail = new htmlMimeMail();
$macroArray = array(
"CUSTOMER_NAME" => $this->orderSum['name'],
"ORDER_ID" => $this->orderSum['cart_order_id'],
"ORDER_URL" => $glob['storeURL']."/index.php?_g=co&_a=viewOrder&cart_order_id=".$this->orderSum['cart_order_id']
);
$text = macroSub($lang['email']['order_acknowledgement_body'],$macroArray);
unset($macroArray);
$mail->setText($text);
$mail->setReturnPath($this->orderSum['email']);
$mail->setFrom($config['masterName'].' <'.$config['masterEmail'].'>');
$mail->setSubject(macroSub($lang['email']['order_acknowledgement_subject'],array("ORDER_ID" => $this->orderSum['cart_order_id'])));
$mail->setHeader('X-Mailer', 'CubeCart Mailer');
$mail->send(array($this->orderSum['email']), $config['mailMethod']);
}
}
?>

View File

@@ -0,0 +1,354 @@
<?php
/*
+--------------------------------------------------------------------------
| CubeCart 4
| ========================================
| CubeCart is a registered trade mark of Devellion Limited
| Copyright Devellion Limited 2006. All rights reserved.
| Devellion Limited,
| 5 Bridge Street,
| Bishops Stortford,
| HERTFORDSHIRE.
| CM23 2JU
| UNITED KINGDOM
| http://www.devellion.com
| UK Private Limited Company No. 5323904
| ========================================
| Web: http://www.cubecart.com
| Email: info (at) cubecart (dot) com
| License Type: CubeCart is NOT Open Source Software and Limitations Apply
| Licence Info: http://www.cubecart.com/site/faq/license.php
+--------------------------------------------------------------------------
| shoppingCart.php
| ========================================
| The Shopping Cart Class
+--------------------------------------------------------------------------
*/
class cart {
var $cartArray;
function cartContents($sqlValue) {
if (!empty($sqlValue)) {
$this->cartArray = unserialize(stripslashes($sqlValue));
return $this->cartArray;
}
return false;
}
function add($productId, $quantity, $options) {
global $config,$db,$glob;
// SO: FIX FOR CHECKOUT FLOW
/* AL: Removed for 1 step CO
$this->setVar(1,"currentStep");
$this->setVar(2,"stepLimit");
*/
// EO: FIX FOR CHECKOUT FLOW
$productKey = $productId.":".$this->buildOptions($options);
if (isset($this->cartArray['conts'][$productKey]['quantity']) && $this->cartArray['conts'][$productKey]['quantity'] > 0) {
$this->cartArray['conts'][$productKey]['quantity'] += $quantity;
} else {
$this->cartArray['conts'][$productKey]['quantity'] = $quantity;
}
/* stock on add to basket for later version maybe
$this->stock($productId,$quantity,"-");
*/
//print_r($this->cartArray);
//die;
return (!$this->sqlValue()) ? $this->error() : $this->cartArray;
}
function addCert($certArray) {
// SO: FIX FOR CHECKOUT FLOW
/* AL: Removed for 1 step CO
$this->setVar(1,"currentStep");
$this->setVar(2,"stepLimit");
*/
// EO: FIX FOR CHECKOUT FLOW
$randCode = 'v'.time().'-'.rand(1000, 9999);
$this->cartArray['conts'][$randCode]['custom'] = 1;
$this->cartArray['conts'][$randCode]['quantity'] = 1;
array_walk($certArray, array(&$this, 'sanitize'));
$this->cartArray['conts'][$randCode]['gcInfo'] = $certArray;
return (!$this->sqlValue()) ? $this->error() : $this->cartArray;
}
function sanitize(&$value, $key) {
$value = stripslashes(html_entity_decode_utf8($value, ENT_COMPAT, 'UTF-8'));
$value = htmlentities(strip_tags($value), ENT_QUOTES, 'UTF-8');
}
function setVar($var, $varName, $arrayName = '',$i = '') {
## unset old delivery address and add new
if (is_array($var)) {
foreach ($var as $key => $value) {
# $var[$key] = str_replace(array("\'", "'"), "&#39;", stripslashes(strip_tags($value)));
$var[$key] = htmlspecialchars(stripslashes(strip_tags($value)), ENT_QUOTES);
}
} else {
# $var = str_replace(array("\'", "'"), "&#39;", stripslashes(strip_tags($var)));
$var = htmlspecialchars(stripslashes(strip_tags($var)), ENT_QUOTES);
}
if (empty($arrayName)) {
unset($this->cartArray[$varName]);
$this->cartArray[$varName] = $var;
return (!$this->sqlValue()) ? $this->error() : $this->cartArray;
} else {
if (isset($this->cartArray[$arrayName][$i][$varName])) {
unset($this->cartArray[$arrayName][$i][$varName]);
}
$this->cartArray[$arrayName][$i][$varName] = $var;
return (!$this->sqlValue()) ? $this->error() : $this->cartArray;
}
}
function unsetVar($varName) {
unset($this->cartArray[$varName]);
return (!$this->sqlValue()) ? $this->error() : $this->cartArray;
}
function remove($productKey) {
global $config, $db, $glob;
// SO: FIX FOR CHECKOUT FLOW
/* AL: Removed for 1 step CO
$this->setVar(1,"currentStep");
$this->setVar(2,"stepLimit");
*/
// EO: FIX FOR CHECKOUT FLOW
$productId = $this->getProductId($productKey);
$quantity = $this->cartArray['conts'][$productKey]['quantity'];
/* stock on add to basket for later version maybe
$this->stock($productId, $quantity,"+");
*/
unset($this->cartArray['conts'][$productKey]);
return (!$this->sqlValue()) ? $this->error() : $this->cartArray;
}
function update($productKey, $quantity) {
$quantity = ceil($quantity);
$productId = $this->getProductId($productKey);
$quantityOld = $this->cartArray['conts'][$productKey]['quantity'];
/*
if ($quantity<$quantityOld) {
## put them back
$difference = $quantityOld - $quantity;
$sign = "+";
} else if ($quantity>$quantityOld) {
## take some more
$difference = $quantity - $quantityOld;
$sign = "-";
}
$this->stock($productId, $difference, $sign);
*/
if ($quantity > 0) {
$this->cartArray['conts'][$productKey]['quantity'] = $quantity;
} else {
unset($this->cartArray['conts'][$productKey]);
}
return (!$this->sqlValue()) ? $this->error() : $this->cartArray;
}
function sqlValue() {
global $db, $glob;
$cartData['basket'] = "'".serialize($this->cartArray)."'";
## sync database to array
$update = $db->update($glob['dbprefix']."CubeCart_sessions", $cartData, 'sessId='.$db->mySQLSafe($GLOBALS[CC_SESSION_NAME]));
return ($update) ? true : false;
}
function noItems() {
$total = 0;
if (is_array($this->cartArray['conts'])) {
foreach ($this->cartArray['conts'] as $key => $value) {
$total = $this->cartArray['conts'][$key]['quantity'] + $total;
}
return $total;
}
return $total;
}
function buildOptions($options) {
if (is_array($options)) {
foreach ($options as $key => $value) {
if (!empty($value)) {
$option[] = strip_tags(stripslashes($value));
}
}
if (!empty($option)) {
return implode('|', $option);
}
}
return false;
/*
$optionStr = '';
if (is_array($options)) {
$amount = count($options);
$i=1;
foreach ($options as $value) {
$optionStr .= $value;
if ($i<$amount) {
$optionStr .= "|";
}
$i++;
}
return $optionStr;
}
return false;
*/
}
function getOptions($productKey) {
$options = explode(":", $productKey);
return $options[1];
}
function getProductId($productKey) {
$options = explode(":", $productKey);
return $options[0];
}
/* Maybe for a later version gets v complex
function returnStock() {
global $db, $glob;
if (is_array($this->cartArray['conts'])) {
foreach ($this->cartArray['conts'] as $key => $value) {
$prodId = $this->getProductId($key);
## put the products back
$useStock = $db->select("SELECT useStockLevel FROM ".$glob['dbprefix']."CubeCart_inventory WHERE productId = ".$prodId);
if($useStock[0]['useStockLevel']==1 && $config['stock_change_time']==0){
$query = "UPDATE ".$glob['dbprefix']."CubeCart_inventory SET stock_level = stock_level + ".$this->cartArray['conts'][$key]['quantity']." WHERE productId = ".$prodId;
$db->misc($query);
}
}
}
}
*/
function emptyCart($keepStock = false) {
global $config;
## lets see if we need to return stock
/* For a later release maybe
if ($keepStock == false && $config['stock_change_time'] == 1) {
$this->returnStock();
}
*/
unset($this->cartArray);
return (!$this->sqlValue()) ? $this->error() : $this->cartArray;
}
function addCoupon($code) {
global $glob,$config,$db;
## Look up code
$coupon = $db->select("SELECT * FROM ".$glob['dbprefix']."CubeCart_Coupons WHERE code = ".$db->mySQLSafe($code)." AND status = 1");
## Validate
if ($coupon) {
if ($coupon[0]['allowed_uses'] > 0 && $coupon[0]['count'] == $coupon[0]['allowed_uses']) {
## used too many times
$this->setVar(1, "codeResult");
} else if (!empty($coupon[0]['expires']) && (strtotime($coupon[0]['expires']) < time())) {
## coupon expired
$this->setVar(2, "codeResult");
} else {
## success
$this->setVar(0,"codeResult");
$this->setVar($coupon[0]['code'],"code");
$this->setVar($coupon[0]['discount_percent'],"discount_percent");
$this->setVar($coupon[0]['discount_price'],"discount_price");
## Will have a cart id if it is a gift certificate therefore if subtotal < gift cert it needs to retan value
if(!empty($coupon[0]['cart_order_id'])) {
$this->setVar(true,"code_is_purchased");
}
## add count = count + 1
$record['count'] = "count + 1";
$where = "id = ".$coupon[0]['id'];
$update = $db->update($glob['dbprefix']."CubeCart_Coupons", $record, $where);
}
} else {
## coupon not found
$this->setVar(3, "codeResult");
}
return $this->cartArray;
}
function removeCoupon($code) {
global $glob, $config, $db;
if($this->cartArray["code_is_purchased"] == true && $this->cartArray["code_remainder"]>0) {
$record['discount_price'] = $db->mySQLSafe($this->cartArray["discount_price"]);
} else {
## subtract count = count - 1
$record['count'] = "count - 1";
}
$where = "code = ".$db->mySQLSafe(base64_decode($code));
$update = $db->update($glob['dbprefix']."CubeCart_Coupons", $record, $where);
$this->unsetVar("codeResult");
$this->unsetVar("code");
$this->unsetVar("discount_percent");
$this->unsetVar("discount_price");
$this->unsetVar("code_is_purchased");
return $this->cartArray;
}
function addByCode($code) {
global $glob,$config,$db;
$result = $db->select("SELECT productId FROM ".$glob['dbprefix']."CubeCart_inventory WHERE productCode = ".$db->mySQLSafe($code));
if ($result) {
## check for product options (if so go to view product page)
$noOpts = $db->numrows("SELECT product FROM ".$glob['dbprefix']."CubeCart_options_bot WHERE product = ".$db->mySQLSafe($result[0]['productId']));
if ($noOpts>0) {
httpredir("index.php?_a=viewProd&productId=".$result[0]['productId']."&notice=1");
} else {
$this->add($result[0]['productId'],1,"");
httpredir(currentPage());
}
}
}
/* maybe for a later version
function stock($productId, $quantity, $sign) {
global $config,$glob,$db;
if ($quantity>0) {
## check product is set to use stock control
$stock = $db->select("SELECT useStockLevel, stock_level FROM ".$glob['dbprefix']."CubeCart_inventory","productId = ".$db->mySQLSafe($productId));
## change stock if product is set to use stock control
if($config['stock_change_time']==1 && $stock[0]['useStockLevel']==1) {
$query = "UPDATE ".$glob['dbprefix']."CubeCart_inventory SET stock_level = stock_level ".$sign." ".$quantity." WHERE productId = ".$db->mySQLSafe($productId);
$update = $db->misc($query);
}
}
}
*/
function error() {
return "<b style='font-family: Arial, Helvetica, sans-serif; color: #0B70CE;'>Cart Error</b><br />\n<span style='font-family: Arial, Helvetica, sans-serif; color: #000000;'>There was an error updating the basket.</span><br />\n";
}
}
?>

View File

@@ -0,0 +1,415 @@
<?php
/*
+--------------------------------------------------------------------------
| CubeCart 4
| ========================================
| CubeCart is a registered trade mark of Devellion Limited
| Copyright Devellion Limited 2006. All rights reserved.
| Devellion Limited,
| 5 Bridge Street,
| Bishops Stortford,
| HERTFORDSHIRE.
| CM23 2JU
| UNITED KINGDOM
| http://www.devellion.com
| UK Private Limited Company No. 5323904
| ========================================
| Web: http://www.cubecart.com
| Email: info (at) cubecart (dot) com
| License Type: CubeCart is NOT Open Source Software and Limitations Apply
| Licence Info: http://www.cubecart.com/site/faq/license.php
+--------------------------------------------------------------------------
| db.php
| ========================================
| Database Class
+--------------------------------------------------------------------------
*/
if (class_exists('db')) {
return;
}
class db {
var $query;
var $db;
var $queryArray = array();
function db() {
global $glob;
$this->db = mysql_connect($glob['dbhost'], $glob['dbusername'], $glob['dbpassword']) or die(mysql_error());
if (!$this->db) die($this->debug(true));
$selectdb = mysql_select_db($glob['dbdatabase'], $this->db);
if (!$selectdb) die ($this->debug());
}
function select($query, $maxRows = 0, $pageNum = 0) {
$this->query = $query;
$this->queryArray[] = $query;
## start limit if $maxRows is greater than 0
if ($maxRows > 0) {
$startRow = $pageNum * $maxRows;
$query = sprintf("%s LIMIT %d, %d", $query, $startRow, $maxRows);
}
$result = mysql_query($query);
if ($this->error()) die ($this->debug());
if (mysql_num_rows($result) >= 1) {
for ($n=0; $n < mysql_num_rows($result); $n++) {
$row = mysql_fetch_assoc($result);
$output[$n] = $row;
}
return $output;
} else {
return false;
}
}
function misc($query, $debug = true) {
$this->query = $query;
$result = mysql_query($query);
if ($this->error() && $debug == true) die ($this->debug());
return ($result) ? true : false;
}
function numrows($query) {
$this->query = $query;
$result = mysql_query($query);
return mysql_num_rows($result);
}
function getRows($query) {
$this->query = $query;
$result = mysql_query($query);
$tables = array();
while ($row = mysql_fetch_row($result)) {
$tables[] = $row;
}
return $tables;
}
function insert($tablename, $record) {
if (!is_array($record)) die($this->debug("array", "Insert", $tablename));
foreach ($record as $field => $value) {
$fields[] = sprintf("`%s`", $field);
$values[] = sprintf("%s", $value);
}
$this->query = sprintf("INSERT INTO %s (%s) VALUES (%s);", $tablename, implode(',', $fields), implode(',', $values));
mysql_query($this->query);
if ($this->error()) die ($this->debug());
return ($this->affected() > 0) ? true : false;
}
function update($tablename, $record, $where = '') {
if(!is_array($record)) die ($this->debug("array", "Update", $tablename));
foreach ($record as $field => $value) {
$set[] = sprintf("`%s` = %s", $field, $value);
}
if(!empty($where)) {
if (is_array($where)) {
foreach ($where as $field => $value) {
$whereArray[] = sprintf("`%s` = '%s'", $field, $value);
}
$where = "WHERE ".implode(' AND ', $whereArray);
} else {
$where = "WHERE ".$where;
}
}
$this->query = sprintf("UPDATE %s SET %s %s;", $tablename, implode(',', $set), $where);
mysql_query($this->query);
if ($this->error()) die ($this->debug());
return ($this->affected() > 0) ? true : false;
}
function categoryNos($cat_id, $sign, $amount = 1) {
global $glob;
if ($cat_id > 0) {
do {
$record['noProducts'] = " noProducts ".$sign.$amount;
$where = "cat_id = ".$cat_id;
$this->update($glob['dbprefix']."CubeCart_category", $record, $where, "");
$query = "SELECT cat_father_id FROM ".$glob['dbprefix']."CubeCart_category WHERE cat_id = ".$cat_id;
$cfi = $this->select($query);
$cat_id = $cfi['0']['cat_father_id'];
}
while ($cat_id > 0);
}
}
function delete($tablename, $where, $limit = '') {
$query = "DELETE from ".$tablename." WHERE ".$where;
if (!empty($limit)) $query .= " LIMIT " . $limit;
$this->query = $query;
mysql_query($query);
if ($this->error()) die ($this->debug());
return ($this->affected() > 0) ? true : false;
}
function truncate($tablename) {
$this->query = sprintf('TRUNCATE %s;', $tablename);
mysql_query($this->query);
if ($this->error()) die ($this->debug());
}
/*********************************************/
## Clean SQL Variables (Security Function)
/*********************************************/
function mySQLSafe($value, $quote = "'") {
## Stripslashes
if (get_magic_quotes_gpc()) {
$value = stripslashes($value);
}
## Strip quotes if already in
$value = str_replace(array("\'","'"), "&#39;", $value);
## Quote value
if (function_exists('mysql_real_escape_string')) {
$value = mysql_real_escape_string($value, $this->db);
} else {
$value = mysql_escape_string($value, $this->db);
}
$value = $quote . trim($value) . $quote;
return $value;
}
function sqldumptable($table, $drop, $structure, $data) {
$tabledump = '';
if ($drop == true && $structure == true) {
$tabledump .= "-- --------------------------------------------------------\n\nDROP TABLE IF EXISTS ".$table.";\n\n";
}
if ($structure == true) {
$tabledump .= "-- --------------------------------------------------------\n\n-- \n-- Table structure for table `".$table."`\n--\n\nCREATE TABLE ".$table." (\n";
$firstfield = true;
$query = "SHOW FIELDS FROM ".$table;
$this->query = $query;
## get columns and spec
$fields = mysql_query($query);
while ($field = mysql_fetch_array($fields)) {
if (!$firstfield) {
$tabledump .= ",\n";
} else {
$firstfield = 0;
}
$tabledump .= " ".$field['Field']." ".$field['Type'];
if (!empty($field["Default"])) $tabledump .= " DEFAULT '".$field['Default']."'";
if ($field['Null'] != "YES") $tabledump .= " NOT NULL";
if (!empty($field['Extra'])) $tabledump .= " ".$field['Extra'];
}
mysql_free_result($fields);
## get keys list
$keys = mysql_query("SHOW KEYS FROM ".$table);
while ($key = mysql_fetch_array($keys)) {
$kname = $key['Key_name'];
if ($kname != "PRIMARY" and $key['Non_unique'] == false) $kname="UNIQUE|".$kname;
if (!is_array($index[$kname])) $index[$kname] = array();
$index[$kname][] = $key['Column_name'];
}
mysql_free_result($keys);
## get each key info
while (list($kname, $columns) = @each($index)) {
$tabledump .= ",\n";
$colnames=implode($columns,",");
if ($kname == "PRIMARY") {
// do primary key
$tabledump .= " PRIMARY KEY (".$colnames.")";
} else {
// do standard key
if (substr($kname,0,6) == "UNIQUE") {
// key is unique
$kname=substr($kname,7);
}
$tabledump .= " KEY ".$kname." (".$colnames.")";
}
}
$tabledump .= "\n);\n\n";
}
if ($data == true) {
## get data
$rows = mysql_query("SELECT * FROM ".$table);
$numfields = mysql_num_fields($rows);
if ($numfields > 0) $tabledump .="--\n-- Dumping data for table `".$table."`\n--\n\n";
while ($row = mysql_fetch_array($rows)) {
$tabledump .= "INSERT INTO ".$table." VALUES(";
$fieldcounter = -1;
$firstfield = true;
## get each field's data
while (++$fieldcounter<$numfields) {
if (!$firstfield) {
$tabledump.=', ';
} else {
$firstfield = 0;
}
if (!isset($row[$fieldcounter])) {
$tabledump .= "NULL";
} else {
$tabledump .= "'".mysql_escape_string($row[$fieldcounter])."'";
}
}
$tabledump .= ");\n";
}
mysql_free_result($rows);
}
return $tabledump;
}
// This function has been built to prevent brute force attacks
function blocker($user, $level, $time, $login, $loc) {
global $glob;
$expireTime = time()-($time*5);
$this->delete($glob['dbprefix']."CubeCart_blocker","lastTime<".$expireTime);
$query = "SELECT * FROM ".$glob['dbprefix']."CubeCart_blocker WHERE `browser` = ".$this->mySQLSafe($_SERVER['HTTP_USER_AGENT'])." AND `ip` = ".$this->mySQLSafe(get_ip_address())." AND `loc`= '".$loc."'";
$blackList = $this->select($query);
if ($blackList && $blackList[0]['blockTime']>time()) {
// do nothing the user is still banned
return true;
} else if ($blackList && $blackList[0]['blockTime']>0 && $blackList[0]['blockTime']<time() && $blackList[0]['blockLevel'] == $level) {
## delete the db row as user is no longer banned
$this->delete($glob['dbprefix']."CubeCart_blocker","id=".$blackList[0]['id']);
return false;
} else if ($blackList && !$login && $blackList[0]['blockTime'] == false) {
$newdata['lastTime'] = time();
## If last attempt was more than the time limit ago we need to set the level to one
## This stops a consecutive fail weeks later blocking on first attempt
$timeAgo = time() - $time;
$newdata['blockLevel'] = ($blackList[0]['lastTime']<$timeAgo) ? 1 : $blackList[0]['blockLevel']+1;
if ($newdata['blockLevel']==$level) {
$newdata['blockTime'] = time() + $time;
$this->update($glob['dbprefix']."CubeCart_blocker", $newdata, "id=".$blackList[0]['id'],$stripQuotes="");
return true;
} else {
$newdata['blockTime'] = 0;
$this->update($glob['dbprefix']."CubeCart_blocker", $newdata, "id=".$blackList[0]['id'],$stripQuotes="");
return false;
}
} else if (!$blackList && !$login) {
## insert
$newdata['blockLevel'] = 1;
$newdata['blockTime'] = 0;
$newdata['browser'] = $this->mySQLSafe($_SERVER['HTTP_USER_AGENT']);
$newdata['ip'] = $this->mySQLSafe(get_ip_address());
$newdata['username'] = $this->mySQLSafe($user);
$newdata['loc'] = "'".$loc."'";
$newdata['lastTime'] = time();
$this->insert($glob['dbprefix']."CubeCart_blocker", $newdata);
return false;
}
}
function debug($type = '', $action = '', $tablename = '') {
switch ($type) {
case "connect":
$message = "MySQL Error Occured";
$result = mysql_errno() . ": " . mysql_error();
$query = "";
$output = "Could not connect to the database. Be sure to check that your database connection settings are correct and that the MySQL server in running.";
break;
case "array":
$message = $action." Error Occured";
$result = "Could not update ".$tablename." as variable supplied must be an array.";
$query = "";
$output = "Sorry an error has occured accessing the database. Be sure to check that your database connection settings are correct and that the MySQL server in running.";
break;
default:
if (mysql_errno($this->db)) {
$message = "MySQL Error Occured";
$result = mysql_errno($this->db) . ": " . mysql_error($this->db);
$output = "Sorry an error has occured accessing the database. Be sure to check that your database connection settings are correct and that the MySQL server in running.";
} else {
$message = "MySQL Query Executed Succesfully.";
$result = mysql_affected_rows($this->db) . " Rows Affected";
$output = "view logs for details";
}
$linebreaks = array("\n", "\r");
$query = (!empty($this->query)) ? "<strong>SQL:</strong><br /> " . str_replace($linebreaks, " ", $this->query) : '';
}
$output = "<h1 style='font-family: Arial, Helvetica, sans-serif; color: #0B70CE;'>".$message."</h1>\n<p style='font-family: Arial, Helvetica, sans-serif; color: #000000;'><strong>Error Message:</strong><br/>".$result."</p>\n";
if (!empty($query)) $output .= "<p style='font-family: Courier New, Courier, mono; border: 1px dashed #666666; padding: 10px; color: #000000;'>".$query."</p>\n";
return $output;
}
function getFulltextIndex($table = 'inventory', $prefix = false) {
global $glob;
if (is_array($table)) {
foreach ($table as $name) {
$fieldlist[$name] = $this->getFulltextIndex($name);
}
} else {
$sql = sprintf("SHOW INDEX FROM %sCubeCart_%s;", $glob['dbprefix'], $table);
$query = mysql_query($sql);
while($index = mysql_fetch_assoc($query)) {
if ($index['Index_type'] == 'FULLTEXT' && $index['Key_name'] == 'fulltext') {
if ($prefix) {
$fieldlist[] = sprintf('%s.%s', $prefix, $index['Column_name']);
} else {
$fieldlist[] = $index['Column_name'];
}
}
}
}
return $fieldlist;
}
function serverVersion() {
return mysql_get_server_info($this->db);
}
function error() {
return (mysql_errno($this->db))? true : false;
}
function errorstring() {
return mysql_error($this->db);
}
function insertid() {
return mysql_insert_id($this->db);
}
function affected() {
return mysql_affected_rows($this->db);
}
function close() {
mysql_close($this->db);
}
## New for 4.1.x
function getFields($table) {
global $glob;
$list = mysql_list_fields($glob['dbdatabase'], $table, $this->db);
$cols = mysql_num_fields($list);
for ($i = 0; $i < $cols; $i++) {
$array = (array) mysql_fetch_field($list, $i);
$return[$array['name']] = $array['name'];
}
return $return;
}
}
?>

Binary file not shown.

View File

@@ -0,0 +1,243 @@
<?php
/*
+--------------------------------------------------------------------------
| CubeCart 4
| ========================================
| CubeCart is a registered trade mark of Devellion Limited
| Copyright Devellion Limited 2006. All rights reserved.
| Devellion Limited,
| 5 Bridge Street,
| Bishops Stortford,
| HERTFORDSHIRE.
| CM23 2JU
| UNITED KINGDOM
| http://www.devellion.com
| UK Private Limited Company No. 5323904
| ========================================
| Web: http://www.cubecart.com
| Email: info (at) cubecart (dot) com
| License Type: CubeCart is NOT Open Source Software and Limitations Apply
| Licence Info: http://www.cubecart.com/site/faq/license.php
+--------------------------------------------------------------------------
| gd.inc.php
| ========================================
| GD Class
+--------------------------------------------------------------------------
*/
class gd {
var $config;
var $glob;
var $img;
var $rootpath;
function gd($imgfile = '', $width = 0, $height = 0) {
global $config, $glob, $rootpath;
$this->config = $config;
$this->glob = $glob;
$this->rootpath = $rootpath;
## Detect image format
$this->img["format"] = ereg_replace(".*\.(.*)$", "\\1", $imgfile);
$this->img["format"] = strtoupper($this->img["format"]);
if ($config['gdversion']) {
if (!file_exists($imgfile)) {
echo 'no file at '.$imgfile;
exit;
}
$img = getimagesize($imgfile);
$this->img['format'] = $img[2];
switch($img[2]) {
case IMAGETYPE_JPEG:
$this->img["src"] = imagecreatefromjpeg($imgfile);
break;
case IMAGETYPE_PNG:
$this->img["src"] = imagecreatefrompng($imgfile);
break;
case IMAGETYPE_GIF:
$this->img["src"] = imagecreatefromgif($imgfile);
break;
default:
echo "Filetype unsupported!";
exit;
}
if ($width>0 && $height>0) {
$this->img["width"] = $width;
$this->img["height"] = $height;
} else {
@$this->img["width"] = imagesx($this->img["src"]);
@$this->img["height"] = imagesy($this->img["src"]);
}
## Default JPEG quality
$this->img["quality"] = $this->config['gdquality'];
} else {
return false;
}
}
function size_custom($width = 100, $height = 100) {
$this->img["width_thumb"] = $width;
$this->img["height_thumb"] = $height;
}
function size_width($size = 100) {
$this->img["width_thumb"] = $size;
@$this->img["height_thumb"] = ($this->img["width_thumb"]/$this->img["width"])*$this->img["height"];
}
function size_height($size = 100) {
$this->img["height_thumb"] = $size;
@$this->img["width_thumb"] = ($this->img["height_thumb"]/$this->img["height"])*$this->img["width"];
}
function size_auto($size = 100) {
// size automatically
if ($this->img["width"] >= $this->img["height"]) {
$this->img["width_thumb"] = $size;
@$this->img["height_thumb"] = ($this->img["width_thumb"]/$this->img["width"])*$this->img["height"];
} else {
$this->img["height_thumb"] = $size;
@$this->img["width_thumb"] = ($this->img["height_thumb"]/$this->img["height"])*$this->img["width"];
}
}
function jpeg_quality($quality = 80) {
$this->img["quality"]=$quality;
}
function randImage($rand) {
## Generate a CAPTCHA image
if (!defined('CC_ROOT_DIR')) define('CC_ROOT_DIR', $this->rootPath);
## Define some default colours
$bgColor = imagecolorallocate ($this->img["src"], 255, 255, 255);
$textColor = imagecolorallocate ($this->img["src"], 0, 0, 0);
$lineColor = imagecolorallocate ($this->img["src"], 215, 215, 215);
## Add Random polygons
$noise_x = $this->img["width"] - 5;
$noise_y = $this->img["height"] - 2;
for ($i=0; $i<3; $i++) {
$polyCoords = array(
rand(5, $noise_x), rand(5, $noise_y),
rand(5, $noise_x), rand(5, $noise_y),
rand(5, $noise_x), rand(5, $noise_y),
rand(5, $noise_x), rand(5, $noise_y),
rand(5, $noise_x), rand(5, $noise_y),
rand(5, $noise_x), rand(5, $noise_y),
rand(5, $noise_x), rand(5, $noise_y),
rand(5, $noise_x), rand(5, $noise_y),
rand(5, $noise_x), rand(5, $noise_y),
rand(5, $noise_x), rand(5, $noise_y),
rand(5, $noise_x), rand(5, $noise_y),
rand(5, $noise_x), rand(5, $noise_y)
);
$randomcolor = imagecolorallocate($this->img["src"], rand(150, 255), rand(150, 255),rand(150, 255));
imagefilledpolygon($this->img["src"], $polyCoords, 6, $randomcolor);
}
## write the random chars
$font = imageloadfont(CC_ROOT_DIR.CC_DS."classes".CC_DS."gd".CC_DS."fonts".CC_DS."anonymous.gdf");
imagestring($this->img["src"], $font, 3, 0, $rand, $textColor);
## Add Random noise
for ($i = 0; $i < 25; $i++) {
$rx1 = rand(0,$this->img["width"]);
$rx2 = rand(0,$this->img["width"]);
$ry1 = rand(0,$this->img["height"]);
$ry2 = rand(0,$this->img["height"]);
$rcVal = rand(0,255);
$rc1 = imagecolorallocate($this->img["src"],rand(0,255),rand(0,255),rand(100,255));
imageline ($this->img["src"], $rx1, $ry1, $rx2, $ry2, $rc1);
}
$this->show(1);
}
function show($noThumb = false) {
global $config;
@header("Expires: " . gmdate("D, d M Y H:i:s") . " GMT");
@header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
@header("Cache-Control: no-store, no-cache, must-revalidate");
@header("Cache-Control: post-check=0, pre-check=0", false);
@header("Pragma: no-cache");
@header("Content-Type: ".image_type_to_mime_type($this->img["format"]));
if ($noThumb) {
$this->img["width_thumb"] = $this->img["width"];
$this->img["height_thumb"] = $this->img["height"];
}
if ($config['gdversion'] >= 2) {
$this->img["des"] = imagecreatetruecolor($this->img["width_thumb"],$this->img["height_thumb"]);
@imagecopyresampled ($this->img["des"], $this->img["src"], 0, 0, 0, 0, $this->img["width_thumb"],$this->img["height_thumb"], $this->img["width"], $this->img["height"]);
} else if ($config['gdversion'] == 1) {
$this->img["des"] = imagecreate($this->img["width_thumb"],$this->img["height_thumb"]);
@imagecopyresized ($this->img["des"], $this->img["src"], 0, 0, 0, 0, $this->img["width_thumb"],$this->img["height_thumb"], $this->img["width"], $this->img["height"]);
}
if ($config['gdversion']>0) {
@touch($this->img["des"]);
switch($this->img['format']) {
case IMAGETYPE_JPEG:
imagejpeg($this->img["des"], '', $this->img["quality"]);
break;
case IMAGETYPE_PNG:
imagepng($this->img["des"]);
break;
case IMAGETYPE_GIF:
imagegif($this->img["des"]);
break;
}
imagedestroy($this->img["des"]);
}
}
function save($save = '', $noThumb = false) {
global $config;
if ($noThumb) {
$this->img["width_thumb"] = $this->img["width"];
$this->img["height_thumb"] = $this->img["height"];
}
if ($config['gdversion'] >= 2) {
$this->img["des"] = imagecreatetruecolor($this->img["width_thumb"],$this->img["height_thumb"]);
@imagecopyresampled ($this->img["des"], $this->img["src"], 0, 0, 0, 0, $this->img["width_thumb"], $this->img["height_thumb"], $this->img["width"], $this->img["height"]);
} else if ($config['gdversion'] == 1) {
$this->img["des"] = imagecreate($this->img["width_thumb"],$this->img["height_thumb"]);
@imagecopyresized ($this->img["des"], $this->img["src"], 0, 0, 0, 0, $this->img["width_thumb"], $this->img["height_thumb"], $this->img["width"], $this->img["height"]);
}
if ($config['gdversion']>0) {
switch($this->img['format']) {
case IMAGETYPE_JPEG:
imagejpeg($this->img["des"], $save, $this->img["quality"]);
break;
case IMAGETYPE_PNG:
imagepng($this->img["des"], $save);
break;
case IMAGETYPE_GIF:
imagegif($this->img["des"], $save);
break;
}
imagedestroy($this->img["des"]);
@chmod($this->img["des"], 0644);
}
}
}
?>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,876 @@
<?php
/**
* RFC 822 Email address list validation Utility
*
* What is it?
*
* This class will take an address string, and parse it into it's consituent
* parts, be that either addresses, groups, or combinations. Nested groups
* are not supported. The structure it returns is pretty straight forward,
* and is similar to that provided by the imap_rfc822_parse_adrlist(). Use
* print_r() to view the structure.
*
* How do I use it?
*
* $address_string = 'My Group: "Richard Heyes" <richard@localhost> (A comment), ted@example.com (Ted Bloggs), Barney;';
* $structure = Mail_RFC822::parseAddressList($address_string, 'example.com', TRUE)
* print_r($structure);
*
* @author Richard Heyes <richard@phpguru.org>
* @author Chuck Hagenbuch <chuck@horde.org>
* @version $Revision: 1.1 $
* @package Mail
This version Modded by Alistair Brookbanks - Devellion Limited
*/
class Mail_RFC822
{
/**
* The address being parsed by the RFC822 object.
* @var string $address
*/
var $address = '';
/**
* The default domain to use for unqualified addresses.
* @var string $default_domain
*/
var $default_domain = 'localhost';
/**
* Should we return a nested array showing groups, or flatten everything?
* @var boolean $nestGroups
*/
var $nestGroups = true;
/**
* Whether or not to validate atoms for non-ascii characters.
* @var boolean $validate
*/
var $validate = true;
/**
* The array of raw addresses built up as we parse.
* @var array $addresses
*/
var $addresses = array();
/**
* The final array of parsed address information that we build up.
* @var array $structure
*/
var $structure = array();
/**
* The current error message, if any.
* @var string $error
*/
var $error = null;
/**
* An internal counter/pointer.
* @var integer $index
*/
var $index = null;
/**
* The number of groups that have been found in the address list.
* @var integer $num_groups
* @access public
*/
var $num_groups = 0;
/**
* A variable so that we can tell whether or not we're inside a
* Mail_RFC822 object.
* @var boolean $mailRFC822
*/
var $mailRFC822 = true;
/**
* A limit after which processing stops
* @var int $limit
*/
var $limit = null;
/**
* Sets up the object. The address must either be set here or when
* calling parseAddressList(). One or the other.
*
* @access public
* @param string $address The address(es) to validate.
* @param string $default_domain Default domain/host etc. If not supplied, will be set to localhost.
* @param boolean $nest_groups Whether to return the structure with groups nested for easier viewing.
* @param boolean $validate Whether to validate atoms. Turn this off if you need to run addresses through before encoding the personal names, for instance.
*
* @return object Mail_RFC822 A new Mail_RFC822 object.
*/
function Mail_RFC822($address = null, $default_domain = null, $nest_groups = null, $validate = null, $limit = null)
{
if (isset($address)) $this->address = $address;
if (isset($default_domain)) $this->default_domain = $default_domain;
if (isset($nest_groups)) $this->nestGroups = $nest_groups;
if (isset($validate)) $this->validate = $validate;
if (isset($limit)) $this->limit = $limit;
}
/**
* Starts the whole process. The address must either be set here
* or when creating the object. One or the other.
*
* @access public
* @param string $address The address(es) to validate.
* @param string $default_domain Default domain/host etc.
* @param boolean $nest_groups Whether to return the structure with groups nested for easier viewing.
* @param boolean $validate Whether to validate atoms. Turn this off if you need to run addresses through before encoding the personal names, for instance.
*
* @return array A structured array of addresses.
*/
function parseAddressList($address = null, $default_domain = null, $nest_groups = null, $validate = null, $limit = null)
{
if (!isset($this->mailRFC822)) {
$obj = new Mail_RFC822($address, $default_domain, $nest_groups, $validate, $limit);
return $obj->parseAddressList();
}
if (isset($address)) $this->address = $address;
if (isset($default_domain)) $this->default_domain = $default_domain;
if (isset($nest_groups)) $this->nestGroups = $nest_groups;
if (isset($validate)) $this->validate = $validate;
if (isset($limit)) $this->limit = $limit;
$this->structure = array();
$this->addresses = array();
$this->error = null;
$this->index = null;
while ($this->address = $this->_splitAddresses($this->address)) {
continue;
}
if ($this->address === false || isset($this->error)) {
return false;
}
// Reset timer since large amounts of addresses can take a long time to
// get here
// *Edit by Brooky* Off if safemode is on because it chucks an error.
if(@ini_get('safe_mode')==FALSE){
set_time_limit(30);
}
// Loop through all the addresses
for ($i = 0; $i < count($this->addresses); $i++){
if (($return = $this->_validateAddress($this->addresses[$i])) === false
|| isset($this->error)) {
return false;
}
if (!$this->nestGroups) {
$this->structure = array_merge($this->structure, $return);
} else {
$this->structure[] = $return;
}
}
return $this->structure;
}
/**
* Splits an address into seperate addresses.
*
* @access private
* @param string $address The addresses to split.
* @return boolean Success or failure.
*/
function _splitAddresses($address)
{
if (!empty($this->limit) AND count($this->addresses) == $this->limit) {
return '';
}
if ($this->_isGroup($address) && !isset($this->error)) {
$split_char = ';';
$is_group = true;
} elseif (!isset($this->error)) {
$split_char = ',';
$is_group = false;
} elseif (isset($this->error)) {
return false;
}
// Split the string based on the above ten or so lines.
$parts = explode($split_char, $address);
$string = $this->_splitCheck($parts, $split_char);
// If a group...
if ($is_group) {
// If $string does not contain a colon outside of
// brackets/quotes etc then something's fubar.
// First check there's a colon at all:
if (strpos($string, ':') === false) {
$this->error = 'Invalid address: ' . $string;
return false;
}
// Now check it's outside of brackets/quotes:
if (!$this->_splitCheck(explode(':', $string), ':'))
return false;
// We must have a group at this point, so increase the counter:
$this->num_groups++;
}
// $string now contains the first full address/group.
// Add to the addresses array.
$this->addresses[] = array(
'address' => trim($string),
'group' => $is_group
);
// Remove the now stored address from the initial line, the +1
// is to account for the explode character.
$address = trim(substr($address, strlen($string) + 1));
// If the next char is a comma and this was a group, then
// there are more addresses, otherwise, if there are any more
// chars, then there is another address.
if ($is_group && substr($address, 0, 1) == ','){
$address = trim(substr($address, 1));
return $address;
} elseif (strlen($address) > 0) {
return $address;
} else {
return '';
}
// If you got here then something's off
return false;
}
/**
* Checks for a group at the start of the string.
*
* @access private
* @param string $address The address to check.
* @return boolean Whether or not there is a group at the start of the string.
*/
function _isGroup($address)
{
// First comma not in quotes, angles or escaped:
$parts = explode(',', $address);
$string = $this->_splitCheck($parts, ',');
// Now we have the first address, we can reliably check for a
// group by searching for a colon that's not escaped or in
// quotes or angle brackets.
if (count($parts = explode(':', $string)) > 1) {
$string2 = $this->_splitCheck($parts, ':');
return ($string2 !== $string);
} else {
return false;
}
}
/**
* A common function that will check an exploded string.
*
* @access private
* @param array $parts The exloded string.
* @param string $char The char that was exploded on.
* @return mixed False if the string contains unclosed quotes/brackets, or the string on success.
*/
function _splitCheck($parts, $char)
{
$string = $parts[0];
for ($i = 0; $i < count($parts); $i++) {
if ($this->_hasUnclosedQuotes($string)
|| $this->_hasUnclosedBrackets($string, '<>')
|| $this->_hasUnclosedBrackets($string, '[]')
|| $this->_hasUnclosedBrackets($string, '()')
|| substr($string, -1) == '\\') {
if (isset($parts[$i + 1])) {
$string = $string . $char . $parts[$i + 1];
} else {
$this->error = 'Invalid address spec. Unclosed bracket or quotes';
return false;
}
} else {
$this->index = $i;
break;
}
}
return $string;
}
/**
* Checks if a string has an unclosed quotes or not.
*
* @access private
* @param string $string The string to check.
* @return boolean True if there are unclosed quotes inside the string, false otherwise.
*/
function _hasUnclosedQuotes($string)
{
$string = explode('"', $string);
$string_cnt = count($string);
for ($i = 0; $i < (count($string) - 1); $i++)
if (substr($string[$i], -1) == '\\')
$string_cnt--;
return ($string_cnt % 2 === 0);
}
/**
* Checks if a string has an unclosed brackets or not. IMPORTANT:
* This function handles both angle brackets and square brackets;
*
* @access private
* @param string $string The string to check.
* @param string $chars The characters to check for.
* @return boolean True if there are unclosed brackets inside the string, false otherwise.
*/
function _hasUnclosedBrackets($string, $chars)
{
$num_angle_start = substr_count($string, $chars[0]);
$num_angle_end = substr_count($string, $chars[1]);
$this->_hasUnclosedBracketsSub($string, $num_angle_start, $chars[0]);
$this->_hasUnclosedBracketsSub($string, $num_angle_end, $chars[1]);
if ($num_angle_start < $num_angle_end) {
$this->error = 'Invalid address spec. Unmatched quote or bracket (' . $chars . ')';
return false;
} else {
return ($num_angle_start > $num_angle_end);
}
}
/**
* Sub function that is used only by hasUnclosedBrackets().
*
* @access private
* @param string $string The string to check.
* @param integer &$num The number of occurences.
* @param string $char The character to count.
* @return integer The number of occurences of $char in $string, adjusted for backslashes.
*/
function _hasUnclosedBracketsSub($string, &$num, $char)
{
$parts = explode($char, $string);
for ($i = 0; $i < count($parts); $i++){
if (substr($parts[$i], -1) == '\\' || $this->_hasUnclosedQuotes($parts[$i]))
$num--;
if (isset($parts[$i + 1]))
$parts[$i + 1] = $parts[$i] . $char . $parts[$i + 1];
}
return $num;
}
/**
* Function to begin checking the address.
*
* @access private
* @param string $address The address to validate.
* @return mixed False on failure, or a structured array of address information on success.
*/
function _validateAddress($address)
{
$is_group = false;
if ($address['group']) {
$is_group = true;
// Get the group part of the name
$parts = explode(':', $address['address']);
$groupname = $this->_splitCheck($parts, ':');
$structure = array();
// And validate the group part of the name.
if (!$this->_validatePhrase($groupname)){
$this->error = 'Group name did not validate.';
return false;
} else {
// Don't include groups if we are not nesting
// them. This avoids returning invalid addresses.
if ($this->nestGroups) {
$structure = new stdClass;
$structure->groupname = $groupname;
}
}
$address['address'] = ltrim(substr($address['address'], strlen($groupname . ':')));
}
// If a group then split on comma and put into an array.
// Otherwise, Just put the whole address in an array.
if ($is_group) {
while (strlen($address['address']) > 0) {
$parts = explode(',', $address['address']);
$addresses[] = $this->_splitCheck($parts, ',');
$address['address'] = trim(substr($address['address'], strlen(end($addresses) . ',')));
}
} else {
$addresses[] = $address['address'];
}
// Check that $addresses is set, if address like this:
// Groupname:;
// Then errors were appearing.
if (!isset($addresses)){
$this->error = 'Empty group.';
return false;
}
for ($i = 0; $i < count($addresses); $i++) {
$addresses[$i] = trim($addresses[$i]);
}
// Validate each mailbox.
// Format could be one of: name <geezer@domain.com>
// geezer@domain.com
// geezer
// ... or any other format valid by RFC 822.
array_walk($addresses, array($this, 'validateMailbox'));
// Nested format
if ($this->nestGroups) {
if ($is_group) {
$structure->addresses = $addresses;
} else {
$structure = $addresses[0];
}
// Flat format
} else {
if ($is_group) {
$structure = array_merge($structure, $addresses);
} else {
$structure = $addresses;
}
}
return $structure;
}
/**
* Function to validate a phrase.
*
* @access private
* @param string $phrase The phrase to check.
* @return boolean Success or failure.
*/
function _validatePhrase($phrase)
{
// Splits on one or more Tab or space.
$parts = preg_split('/[ \\x09]+/', $phrase, -1, PREG_SPLIT_NO_EMPTY);
$phrase_parts = array();
while (count($parts) > 0){
$phrase_parts[] = $this->_splitCheck($parts, ' ');
for ($i = 0; $i < $this->index + 1; $i++)
array_shift($parts);
}
for ($i = 0; $i < count($phrase_parts); $i++) {
// If quoted string:
if (substr($phrase_parts[$i], 0, 1) == '"') {
if (!$this->_validateQuotedString($phrase_parts[$i]))
return false;
continue;
}
// Otherwise it's an atom:
if (!$this->_validateAtom($phrase_parts[$i])) return false;
}
return true;
}
/**
* Function to validate an atom which from rfc822 is:
* atom = 1*<any CHAR except specials, SPACE and CTLs>
*
* If validation ($this->validate) has been turned off, then
* validateAtom() doesn't actually check anything. This is so that you
* can split a list of addresses up before encoding personal names
* (umlauts, etc.), for example.
*
* @access private
* @param string $atom The string to check.
* @return boolean Success or failure.
*/
function _validateAtom($atom)
{
if (!$this->validate) {
// Validation has been turned off; assume the atom is okay.
return true;
}
// Check for any char from ASCII 0 - ASCII 127
if (!preg_match('/^[\\x00-\\x7E]+$/i', $atom, $matches)) {
return false;
}
// Check for specials:
if (preg_match('/[][()<>@,;\\:". ]/', $atom)) {
return false;
}
// Check for control characters (ASCII 0-31):
if (preg_match('/[\\x00-\\x1F]+/', $atom)) {
return false;
}
return true;
}
/**
* Function to validate quoted string, which is:
* quoted-string = <"> *(qtext/quoted-pair) <">
*
* @access private
* @param string $qstring The string to check
* @return boolean Success or failure.
*/
function _validateQuotedString($qstring)
{
// Leading and trailing "
$qstring = substr($qstring, 1, -1);
// Perform check.
return !(preg_match('/(.)[\x0D\\\\"]/', $qstring, $matches) && $matches[1] != '\\');
}
/**
* Function to validate a mailbox, which is:
* mailbox = addr-spec ; simple address
* / phrase route-addr ; name and route-addr
*
* @access public
* @param string &$mailbox The string to check.
* @return boolean Success or failure.
*/
function validateMailbox(&$mailbox)
{
// A couple of defaults.
$phrase = '';
$comment = '';
// Catch any RFC822 comments and store them separately
$_mailbox = $mailbox;
while (strlen(trim($_mailbox)) > 0) {
$parts = explode('(', $_mailbox);
$before_comment = $this->_splitCheck($parts, '(');
if ($before_comment != $_mailbox) {
// First char should be a (
$comment = substr(str_replace($before_comment, '', $_mailbox), 1);
$parts = explode(')', $comment);
$comment = $this->_splitCheck($parts, ')');
$comments[] = $comment;
// +1 is for the trailing )
$_mailbox = substr($_mailbox, strpos($_mailbox, $comment)+strlen($comment)+1);
} else {
break;
}
}
for($i=0; $i<count(@$comments); $i++){
$mailbox = str_replace('('.$comments[$i].')', '', $mailbox);
}
$mailbox = trim($mailbox);
// Check for name + route-addr
if (substr($mailbox, -1) == '>' && substr($mailbox, 0, 1) != '<') {
$parts = explode('<', $mailbox);
$name = $this->_splitCheck($parts, '<');
$phrase = trim($name);
$route_addr = trim(substr($mailbox, strlen($name.'<'), -1));
if ($this->_validatePhrase($phrase) === false || ($route_addr = $this->_validateRouteAddr($route_addr)) === false)
return false;
// Only got addr-spec
} else {
// First snip angle brackets if present.
if (substr($mailbox,0,1) == '<' && substr($mailbox,-1) == '>')
$addr_spec = substr($mailbox,1,-1);
else
$addr_spec = $mailbox;
if (($addr_spec = $this->_validateAddrSpec($addr_spec)) === false)
return false;
}
// Construct the object that will be returned.
$mbox = new stdClass();
// Add the phrase (even if empty) and comments
$mbox->personal = $phrase;
$mbox->comment = isset($comments) ? $comments : array();
if (isset($route_addr)) {
$mbox->mailbox = $route_addr['local_part'];
$mbox->host = $route_addr['domain'];
$route_addr['adl'] !== '' ? $mbox->adl = $route_addr['adl'] : '';
} else {
$mbox->mailbox = $addr_spec['local_part'];
$mbox->host = $addr_spec['domain'];
}
$mailbox = $mbox;
return true;
}
/**
* This function validates a route-addr which is:
* route-addr = "<" [route] addr-spec ">"
*
* Angle brackets have already been removed at the point of
* getting to this function.
*
* @access private
* @param string $route_addr The string to check.
* @return mixed False on failure, or an array containing validated address/route information on success.
*/
function _validateRouteAddr($route_addr)
{
// Check for colon.
if (strpos($route_addr, ':') !== false) {
$parts = explode(':', $route_addr);
$route = $this->_splitCheck($parts, ':');
} else {
$route = $route_addr;
}
// If $route is same as $route_addr then the colon was in
// quotes or brackets or, of course, non existent.
if ($route === $route_addr){
unset($route);
$addr_spec = $route_addr;
if (($addr_spec = $this->_validateAddrSpec($addr_spec)) === false) {
return false;
}
} else {
// Validate route part.
if (($route = $this->_validateRoute($route)) === false) {
return false;
}
$addr_spec = substr($route_addr, strlen($route . ':'));
// Validate addr-spec part.
if (($addr_spec = $this->_validateAddrSpec($addr_spec)) === false) {
return false;
}
}
if (isset($route)) {
$return['adl'] = $route;
} else {
$return['adl'] = '';
}
$return = array_merge($return, $addr_spec);
return $return;
}
/**
* Function to validate a route, which is:
* route = 1#("@" domain) ":"
*
* @access private
* @param string $route The string to check.
* @return mixed False on failure, or the validated $route on success.
*/
function _validateRoute($route)
{
// Split on comma.
$domains = explode(',', trim($route));
for ($i = 0; $i < count($domains); $i++) {
$domains[$i] = str_replace('@', '', trim($domains[$i]));
if (!$this->_validateDomain($domains[$i])) return false;
}
return $route;
}
/**
* Function to validate a domain, though this is not quite what
* you expect of a strict internet domain.
*
* domain = sub-domain *("." sub-domain)
*
* @access private
* @param string $domain The string to check.
* @return mixed False on failure, or the validated domain on success.
*/
function _validateDomain($domain)
{
// Note the different use of $subdomains and $sub_domains
$subdomains = explode('.', $domain);
while (count($subdomains) > 0) {
$sub_domains[] = $this->_splitCheck($subdomains, '.');
for ($i = 0; $i < $this->index + 1; $i++)
array_shift($subdomains);
}
for ($i = 0; $i < count($sub_domains); $i++) {
if (!$this->_validateSubdomain(trim($sub_domains[$i])))
return false;
}
// Managed to get here, so return input.
return $domain;
}
/**
* Function to validate a subdomain:
* subdomain = domain-ref / domain-literal
*
* @access private
* @param string $subdomain The string to check.
* @return boolean Success or failure.
*/
function _validateSubdomain($subdomain)
{
if (preg_match('|^\[(.*)]$|', $subdomain, $arr)){
if (!$this->_validateDliteral($arr[1])) return false;
} else {
if (!$this->_validateAtom($subdomain)) return false;
}
// Got here, so return successful.
return true;
}
/**
* Function to validate a domain literal:
* domain-literal = "[" *(dtext / quoted-pair) "]"
*
* @access private
* @param string $dliteral The string to check.
* @return boolean Success or failure.
*/
function _validateDliteral($dliteral)
{
return !preg_match('/(.)[][\x0D\\\\]/', $dliteral, $matches) && $matches[1] != '\\';
}
/**
* Function to validate an addr-spec.
*
* addr-spec = local-part "@" domain
*
* @access private
* @param string $addr_spec The string to check.
* @return mixed False on failure, or the validated addr-spec on success.
*/
function _validateAddrSpec($addr_spec)
{
$addr_spec = trim($addr_spec);
// Split on @ sign if there is one.
if (strpos($addr_spec, '@') !== false) {
$parts = explode('@', $addr_spec);
$local_part = $this->_splitCheck($parts, '@');
$domain = substr($addr_spec, strlen($local_part . '@'));
// No @ sign so assume the default domain.
} else {
$local_part = $addr_spec;
$domain = $this->default_domain;
}
if (($local_part = $this->_validateLocalPart($local_part)) === false) return false;
if (($domain = $this->_validateDomain($domain)) === false) return false;
// Got here so return successful.
return array('local_part' => $local_part, 'domain' => $domain);
}
/**
* Function to validate the local part of an address:
* local-part = word *("." word)
*
* @access private
* @param string $local_part
* @return mixed False on failure, or the validated local part on success.
*/
function _validateLocalPart($local_part)
{
$parts = explode('.', $local_part);
// Split the local_part into words.
while (count($parts) > 0){
$words[] = $this->_splitCheck($parts, '.');
for ($i = 0; $i < $this->index + 1; $i++) {
array_shift($parts);
}
}
// Validate each word.
for ($i = 0; $i < count($words); $i++) {
if ($this->_validatePhrase(trim($words[$i])) === false) return false;
}
// Managed to get here, so return the input.
return $local_part;
}
/**
* Returns an approximate count of how many addresses are
* in the given string. This is APPROXIMATE as it only splits
* based on a comma which has no preceding backslash. Could be
* useful as large amounts of addresses will end up producing
* *large* structures when used with parseAddressList().
*
* @param string $data Addresses to count
* @return int Approximate count
*/
function approximateCount($data)
{
return count(preg_split('/(?<!\\\\),/', $data));
}
/**
* This is a email validating function seperate to the rest
* of the class. It simply validates whether an email is of
* the common internet form: <user>@<domain>. This can be
* sufficient for most people. Optional stricter mode can
* be utilised which restricts mailbox characters allowed
* to alphanumeric, full stop, hyphen and underscore.
*
* @param string $data Address to check
* @param boolean $strict Optional stricter mode
* @return mixed False if it fails, an indexed array
* username/domain if it matches
*/
function isValidInetAddress($data, $strict = false)
{
$regex = $strict ? '/^([.0-9a-z_-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,4})$/i' : '/^([*+!.&#$|\'\\%\/0-9a-z^_`{}=?~:-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,4})$/i';
if (preg_match($regex, trim($data), $matches)) {
return array($matches[1], $matches[2]);
} else {
return false;
}
}
}
?>

View File

@@ -0,0 +1,820 @@
<?php
/**
* Filename.......: class.html.mime.mail.inc
* Project........: HTML Mime mail class
* Last Modified..: $Date: 2002/07/24 13:14:10 $
* CVS Revision...: $Revision: 1.4 $
* Copyright......: 2001, 2002 Richard Heyes
This version Modded by Alistair Brookbanks - Devellion Limited
*/
require_once(dirname(__FILE__) . '/mimePart.php');
if (class_exists('htmlMimeMail'))
{
return;
}
class htmlMimeMail
{
/**
* The html part of the message
* @var string
*/
var $html;
/**
* The text part of the message(only used in TEXT only messages)
* @var string
*/
var $text;
/**
* The main body of the message after building
* @var string
*/
var $output;
/**
* The alternative text to the HTML part (only used in HTML messages)
* @var string
*/
var $html_text;
/**
* An array of embedded images/objects
* @var array
*/
var $html_images;
/**
* An array of recognised image types for the findHtmlImages() method
* @var array
*/
var $image_types;
/**
* Parameters that affect the build process
* @var array
*/
var $build_params;
/**
* Array of attachments
* @var array
*/
var $attachments;
/**
* The main message headers
* @var array
*/
var $headers;
/**
* Whether the message has been built or not
* @var boolean
*/
var $is_built;
/**
* The return path address. If not set the From:
* address is used instead
* @var string
*/
var $return_path;
/**
* Array of information needed for smtp sending
* @var array
*/
var $smtp_params;
/**
* Constructor function. Sets the headers
* if supplied.
*/
function htmlMimeMail()
{
/**
* Initialise some variables.
*/
global $config;
$this->html_images = array();
$this->headers = array();
$this->is_built = false;
/**
* If you want the auto load functionality
* to find other image/file types, add the
* extension and content type here.
*/
$this->image_types = array(
'gif' => 'image/gif',
'jpg' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'jpe' => 'image/jpeg',
'bmp' => 'image/bmp',
'png' => 'image/png',
'tif' => 'image/tiff',
'tiff' => 'image/tiff',
'swf' => 'application/x-shockwave-flash'
);
/**
* Set these up
*/
$this->build_params['html_encoding'] = 'quoted-printable';
$this->build_params['text_encoding'] = '7bit';
/*
$this->build_params['html_charset'] = 'ISO-8859-1';
$this->build_params['text_charset'] = 'ISO-8859-1';
$this->build_params['head_charset'] = 'ISO-8859-1';
*/
$this->build_params['html_charset'] = 'UTF-8';
$this->build_params['text_charset'] = 'UTF-8';
$this->build_params['head_charset'] = 'UTF-8';
$this->build_params['text_wrap'] = 998;
/**
* Defaults for smtp sending
*/
if (!empty($GLOBALS['HTTP_SERVER_VARS']['HTTP_HOST'])) {
$helo = $GLOBALS['HTTP_SERVER_VARS']['HTTP_HOST'];
} elseif (!empty($GLOBALS['HTTP_SERVER_VARS']['SERVER_NAME'])) {
$helo = $GLOBALS['HTTP_SERVER_VARS']['SERVER_NAME'];
} else {
$helo = 'localhost';
}
if(!isset($config['smtpHost']) OR empty($config['smtpHost'])) {
$this->smtp_params['host'] = 'localhost';
} else {
$this->smtp_params['host'] = $config['smtpHost'];
}
if(!isset($config['smtpPort']) OR empty($config['smtpPort'])) {
$this->smtp_params['port'] = 25;
} else {
$this->smtp_params['port'] = $config['smtpPort'];
}
if(!isset($config['smtpAuth']) OR empty($config['smtpAuth'])) {
$this->smtp_params['auth'] = FALSE;
} else {
$this->smtp_params['auth'] = $config['smtpAuth'];
}
if(!isset($config['smtpUsername']) OR empty($config['smtpUsername'])) {
$this->smtp_params['user'] = '';
} else {
$this->smtp_params['user'] = $config['smtpUsername'];
}
if(!isset($config['smtpPassword']) OR empty($config['smtpPassword'])) {
$this->smtp_params['pass'] = '';
} else {
$this->smtp_params['pass'] = $config['smtpPassword'];
}
$this->smtp_params['helo'] = $helo;
/**
* Make sure the MIME version header is first.
*/
$this->headers['MIME-Version'] = '1.0';
}
/**
* This function will read a file in
* from a supplied filename and return
* it. This can then be given as the first
* argument of the the functions
* add_html_image() or add_attachment().
*/
function getFile($filename)
{
$return = '';
if ($fp = fopen($filename, 'rb')) {
while (!feof($fp)) {
$return .= fread($fp, 1024);
}
fclose($fp);
return $return;
} else {
return false;
}
}
/**
* Accessor to set the CRLF style
*/
function setCrlf($crlf = "\n")
{
if (!defined('CRLF')) {
define('CRLF', $crlf, true);
}
if (!defined('MAIL_MIMEPART_CRLF')) {
define('MAIL_MIMEPART_CRLF', $crlf, true);
}
}
/**
* Accessor to set the SMTP parameters
*/
function setSMTPParams($host = null, $port = null, $helo = null, $auth = null, $user = null, $pass = null)
{
if (!is_null($host)) $this->smtp_params['host'] = $host;
if (!is_null($port)) $this->smtp_params['port'] = $port;
if (!is_null($helo)) $this->smtp_params['helo'] = $helo;
if (!is_null($auth)) $this->smtp_params['auth'] = $auth;
if (!is_null($user)) $this->smtp_params['user'] = $user;
if (!is_null($pass)) $this->smtp_params['pass'] = $pass;
}
/**
* Accessor function to set the text encoding
*/
function setTextEncoding($encoding = '7bit')
{
$this->build_params['text_encoding'] = $encoding;
}
/**
* Accessor function to set the HTML encoding
*/
function setHtmlEncoding($encoding = 'quoted-printable')
{
$this->build_params['html_encoding'] = $encoding;
}
/**
* Accessor function to set the text charset
*/
function setTextCharset($charset = 'UTF-8')
{
$this->build_params['text_charset'] = $charset;
}
/**
* Accessor function to set the HTML charset
*/
function setHtmlCharset($charset = 'UTF-8')
{
$this->build_params['html_charset'] = $charset;
}
/**
* Accessor function to set the header encoding charset
*/
function setHeadCharset($charset = 'UTF-8')
{
$this->build_params['head_charset'] = $charset;
}
/**
* Accessor function to set the text wrap count
*/
function setTextWrap($count = 998)
{
$this->build_params['text_wrap'] = $count;
}
/**
* Accessor to set a header
*/
function setHeader($name, $value)
{
$this->headers[$name] = $value;
}
/**
* Accessor to add a Subject: header
*/
function setSubject($subject)
{
$this->headers['Subject'] = $subject;
}
/**
* Accessor to add a From: header
*/
function setFrom($from)
{
$this->headers['From'] = $from;
}
/**
* Accessor to set the return path
*/
function setReturnPath($return_path)
{
if(@ini_get('safe_mode')==TRUE){
return FALSE;
} else {
$this->return_path = $return_path;
}
}
/**
* Accessor to add a Cc: header
*/
function setCc($cc)
{
$this->headers['Cc'] = $cc;
}
/**
* Accessor to add a Bcc: header
*/
function setBcc($bcc)
{
$this->headers['Bcc'] = $bcc;
}
/**
* Adds plain text. Use this function
* when NOT sending html email
*/
function setText($text = '')
{
$this->text = str_replace("&#39;","'",$text);
}
/**
* Adds a html part to the mail.
* Also replaces image names with
* content-id's.
*/
function setHtml($html, $text = null, $images_dir = null)
{
$this->html = $html;
$this->html_text = $text;
if (isset($images_dir)) {
$this->_findHtmlImages($images_dir);
}
}
/**
* Function for extracting images from
* html source. This function will look
* through the html code supplied by add_html()
* and find any file that ends in one of the
* extensions defined in $obj->image_types.
* If the file exists it will read it in and
* embed it, (not an attachment).
*
* @author Dan Allen
*/
function _findHtmlImages($images_dir)
{
// Build the list of image extensions
while (list($key,) = each($this->image_types)) {
$extensions[] = $key;
}
preg_match_all('/(?:"|\')([^"\']+\.('.implode('|', $extensions).'))(?:"|\')/Ui', $this->html, $images);
for ($i=0; $i<count($images[1]); $i++) {
if (file_exists($images_dir . $images[1][$i])) {
$html_images[] = $images[1][$i];
$this->html = str_replace($images[1][$i], basename($images[1][$i]), $this->html);
}
}
if (!empty($html_images)) {
// If duplicate images are embedded, they may show up as attachments, so remove them.
$html_images = array_unique($html_images);
sort($html_images);
for ($i=0; $i<count($html_images); $i++) {
if ($image = $this->getFile($images_dir.$html_images[$i])) {
$ext = substr($html_images[$i], strrpos($html_images[$i], '.') + 1);
$content_type = $this->image_types[strtolower($ext)];
$this->addHtmlImage($image, basename($html_images[$i]), $content_type);
}
}
}
}
/**
* Adds an image to the list of embedded
* images.
*/
function addHtmlImage($file, $name = '', $c_type='application/octet-stream')
{
$this->html_images[] = array(
'body' => $file,
'name' => $name,
'c_type' => $c_type,
'cid' => md5(uniqid(time()))
);
}
/**
* Adds a file to the list of attachments.
*/
function addAttachment($file, $name = '', $c_type='application/octet-stream', $encoding = 'base64')
{
$this->attachments[] = array(
'body' => $file,
'name' => $name,
'c_type' => $c_type,
'encoding' => $encoding
);
}
/**
* Adds a text subpart to a mime_part object
*/
function &_addTextPart(&$obj, $text)
{
$params['content_type'] = 'text/plain';
$params['encoding'] = $this->build_params['text_encoding'];
$params['charset'] = $this->build_params['text_charset'];
if (is_object($obj)) {
return $obj->addSubpart($text, $params);
} else {
return new Mail_mimePart($text, $params);
}
}
/**
* Adds a html subpart to a mime_part object
*/
function &_addHtmlPart(&$obj)
{
$params['content_type'] = 'text/html';
$params['encoding'] = $this->build_params['html_encoding'];
$params['charset'] = $this->build_params['html_charset'];
if (is_object($obj)) {
return $obj->addSubpart($this->html, $params);
} else {
return new Mail_mimePart($this->html, $params);
}
}
/**
* Starts a message with a mixed part
*/
function &_addMixedPart()
{
$params['content_type'] = 'multipart/mixed';
return new Mail_mimePart('', $params);
}
/**
* Adds an alternative part to a mime_part object
*/
function &_addAlternativePart(&$obj)
{
$params['content_type'] = 'multipart/alternative';
if (is_object($obj)) {
return $obj->addSubpart('', $params);
} else {
return new Mail_mimePart('', $params);
}
}
/**
* Adds a html subpart to a mime_part object
*/
function &_addRelatedPart(&$obj)
{
$params['content_type'] = 'multipart/related';
if (is_object($obj)) {
return $obj->addSubpart('', $params);
} else {
return new Mail_mimePart('', $params);
}
}
/**
* Adds an html image subpart to a mime_part object
*/
function &_addHtmlImagePart(&$obj, $value)
{
$params['content_type'] = $value['c_type'];
$params['encoding'] = 'base64';
$params['disposition'] = 'inline';
$params['dfilename'] = $value['name'];
$params['cid'] = $value['cid'];
$obj->addSubpart($value['body'], $params);
}
/**
* Adds an attachment subpart to a mime_part object
*/
function &_addAttachmentPart(&$obj, $value)
{
$params['content_type'] = $value['c_type'];
$params['encoding'] = $value['encoding'];
$params['disposition'] = 'attachment';
$params['dfilename'] = $value['name'];
$obj->addSubpart($value['body'], $params);
}
/**
* Builds the multipart message from the
* list ($this->_parts). $params is an
* array of parameters that shape the building
* of the message. Currently supported are:
*
* $params['html_encoding'] - The type of encoding to use on html. Valid options are
* "7bit", "quoted-printable" or "base64" (all without quotes).
* 7bit is EXPRESSLY NOT RECOMMENDED. Default is quoted-printable
* $params['text_encoding'] - The type of encoding to use on plain text Valid options are
* "7bit", "quoted-printable" or "base64" (all without quotes).
* Default is 7bit
* $params['text_wrap'] - The character count at which to wrap 7bit encoded data.
* Default this is 998.
* $params['html_charset'] - The character set to use for a html section.
* Default is ISO-8859-1
* $params['text_charset'] - The character set to use for a text section.
* - Default is ISO-8859-1
* $params['head_charset'] - The character set to use for header encoding should it be needed.
* - Default is ISO-8859-1
*/
function buildMessage($params = array())
{
if (!empty($params)) {
while (list($key, $value) = each($params)) {
$this->build_params[$key] = $value;
}
}
if (!empty($this->html_images)) {
foreach ($this->html_images as $value) {
$this->html = str_replace($value['name'], 'cid:'.$value['cid'], $this->html);
}
}
$null = null;
$attachments = !empty($this->attachments) ? true : false;
$html_images = !empty($this->html_images) ? true : false;
$html = !empty($this->html) ? true : false;
$text = isset($this->text) ? true : false;
switch (true) {
case $text AND !$attachments:
$message = &$this->_addTextPart($null, $this->text);
break;
case !$text AND $attachments AND !$html:
$message = &$this->_addMixedPart();
for ($i=0; $i<count($this->attachments); $i++) {
$this->_addAttachmentPart($message, $this->attachments[$i]);
}
break;
case $text AND $attachments:
$message = &$this->_addMixedPart();
$this->_addTextPart($message, $this->text);
for ($i=0; $i<count($this->attachments); $i++) {
$this->_addAttachmentPart($message, $this->attachments[$i]);
}
break;
case $html AND !$attachments AND !$html_images:
if (!is_null($this->html_text)) {
$message = &$this->_addAlternativePart($null);
$this->_addTextPart($message, $this->html_text);
$this->_addHtmlPart($message);
} else {
$message = &$this->_addHtmlPart($null);
}
break;
case $html AND !$attachments AND $html_images:
if (!is_null($this->html_text)) {
$message = &$this->_addAlternativePart($null);
$this->_addTextPart($message, $this->html_text);
$related = &$this->_addRelatedPart($message);
} else {
$message = &$this->_addRelatedPart($null);
$related = &$message;
}
$this->_addHtmlPart($related);
for ($i=0; $i<count($this->html_images); $i++) {
$this->_addHtmlImagePart($related, $this->html_images[$i]);
}
break;
case $html AND $attachments AND !$html_images:
$message = &$this->_addMixedPart();
if (!is_null($this->html_text)) {
$alt = &$this->_addAlternativePart($message);
$this->_addTextPart($alt, $this->html_text);
$this->_addHtmlPart($alt);
} else {
$this->_addHtmlPart($message);
}
for ($i=0; $i<count($this->attachments); $i++) {
$this->_addAttachmentPart($message, $this->attachments[$i]);
}
break;
case $html AND $attachments AND $html_images:
$message = &$this->_addMixedPart();
if (!is_null($this->html_text)) {
$alt = &$this->_addAlternativePart($message);
$this->_addTextPart($alt, $this->html_text);
$rel = &$this->_addRelatedPart($alt);
} else {
$rel = &$this->_addRelatedPart($message);
}
$this->_addHtmlPart($rel);
for ($i=0; $i<count($this->html_images); $i++) {
$this->_addHtmlImagePart($rel, $this->html_images[$i]);
}
for ($i=0; $i<count($this->attachments); $i++) {
$this->_addAttachmentPart($message, $this->attachments[$i]);
}
break;
}
if (isset($message)) {
$output = $message->encode();
$this->output = $output['body'];
$this->headers = array_merge($this->headers, $output['headers']);
// Add message ID header
srand((double)microtime()*10000000);
$message_id = sprintf('<%s.%s@%s>', base_convert(time(), 10, 36), base_convert(rand(), 10, 36), !empty($GLOBALS['HTTP_SERVER_VARS']['HTTP_HOST']) ? $GLOBALS['HTTP_SERVER_VARS']['HTTP_HOST'] : $GLOBALS['HTTP_SERVER_VARS']['SERVER_NAME']);
$this->headers['Message-ID'] = $message_id;
$this->is_built = true;
return true;
} else {
return false;
}
}
/**
* Function to encode a header if necessary
* according to RFC2047
*/
function _encodeHeader($input, $charset = 'UTF-8')
{
preg_match_all('/(\w*[\x80-\xFF]+\w*)/', $input, $matches);
foreach ($matches[1] as $value) {
$replacement = preg_replace('/([\x80-\xFF])/e', '"=" . strtoupper(dechex(ord("\1")))', $value);
$input = str_replace($value, '=?' . $charset . '?Q?' . $replacement . '?=', $input);
}
return $input;
}
/**
* Sends the mail.
*
* @param array $recipients
* @param string $type OPTIONAL
* @return mixed
*/
function send($recipients, $type = 'mail')
{
if (!defined('CRLF')) {
$this->setCrlf($type == 'mail' ? "\n" : "\r\n");
}
if (!$this->is_built) {
$this->buildMessage();
}
switch ($type) {
case 'mail':
$subject = '';
if (!empty($this->headers['Subject'])) {
$subject = $this->_encodeHeader($this->headers['Subject'], $this->build_params['head_charset']);
unset($this->headers['Subject']);
}
// Get flat representation of headers
foreach ($this->headers as $name => $value) {
$headers[] = $name . ': ' . $this->_encodeHeader($value, $this->build_params['head_charset']);
}
$to = $this->_encodeHeader(implode(', ', $recipients), $this->build_params['head_charset']);
if (!empty($this->return_path)) {
$result = mail($to, $subject, $this->output, implode(CRLF, $headers), '-f' . $this->return_path);
} else {
$result = mail($to, $subject, $this->output, implode(CRLF, $headers));
}
// Reset the subject in case mail is resent
if ($subject !== '') {
$this->headers['Subject'] = $subject;
}
// Return
return $result;
break;
case 'smtp':
require_once(dirname(__FILE__) . '/smtp.php');
require_once(dirname(__FILE__) . '/RFC822.php');
$smtp = &smtp::connect($this->smtp_params);
// Parse recipients argument for internet addresses
foreach ($recipients as $recipient) {
$addresses = Mail_RFC822::parseAddressList($recipient, $this->smtp_params['helo'], null, false);
foreach ($addresses as $address) {
$smtp_recipients[] = sprintf('%s@%s', $address->mailbox, $address->host);
}
}
unset($addresses); // These are reused
unset($address); // These are reused
// Get flat representation of headers, parsing
// Cc and Bcc as we go
foreach ($this->headers as $name => $value) {
if ($name == 'Cc' OR $name == 'Bcc') {
$addresses = Mail_RFC822::parseAddressList($value, $this->smtp_params['helo'], null, false);
foreach ($addresses as $address) {
$smtp_recipients[] = sprintf('%s@%s', $address->mailbox, $address->host);
}
}
if ($name == 'Bcc') {
continue;
}
$headers[] = $name . ': ' . $this->_encodeHeader($value, $this->build_params['head_charset']);
}
// Add To header based on $recipients argument
$headers[] = 'To: ' . $this->_encodeHeader(implode(', ', $recipients), $this->build_params['head_charset']);
// Add headers to send_params
$send_params['headers'] = $headers;
$send_params['recipients'] = array_values(array_unique($smtp_recipients));
$send_params['body'] = $this->output;
// Setup return path
if (isset($this->return_path)) {
$send_params['from'] = $this->return_path;
} elseif (!empty($this->headers['From'])) {
$from = Mail_RFC822::parseAddressList($this->headers['From']);
$send_params['from'] = sprintf('%s@%s', $from[0]->mailbox, $from[0]->host);
} else {
$send_params['from'] = 'postmaster@' . $this->smtp_params['helo'];
}
// Send it
if (!$smtp->send($send_params)) {
$this->errors = $smtp->errors;
return false;
}
return true;
break;
}
}
/**
* Use this method to return the email
* in message/rfc822 format. Useful for
* adding an email to another email as
* an attachment. there's a commented
* out example in example.php.
*/
function getRFC822($recipients)
{
// Make up the date header as according to RFC822
$this->setHeader('Date', date('D, d M y H:i:s O'));
if (!defined('CRLF')) {
$this->setCrlf($type == 'mail' ? "\n" : "\r\n");
}
if (!$this->is_built) {
$this->buildMessage();
}
// Return path ?
if (isset($this->return_path)) {
$headers[] = 'Return-Path: ' . $this->return_path;
}
// Get flat representation of headers
foreach ($this->headers as $name => $value) {
$headers[] = $name . ': ' . $value;
}
$headers[] = 'To: ' . implode(', ', $recipients);
return implode(CRLF, $headers) . CRLF . CRLF . $this->output;
}
} // End of class.
?>

View File

@@ -0,0 +1,333 @@
<?php
//
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2002 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Authors: Richard Heyes <richard@phpguru.org> |
// +----------------------------------------------------------------------+
/**
*
* Raw mime encoding class
*
* What is it?
* This class enables you to manipulate and build
* a mime email from the ground up.
*
* Why use this instead of mime.php?
* mime.php is a userfriendly api to this class for
* people who aren't interested in the internals of
* mime mail. This class however allows full control
* over the email.
*
* Eg.
*
* // Since multipart/mixed has no real body, (the body is
* // the subpart), we set the body argument to blank.
*
* $params['content_type'] = 'multipart/mixed';
* $email = new Mail_mimePart('', $params);
*
* // Here we add a text part to the multipart we have
* // already. Assume $body contains plain text.
*
* $params['content_type'] = 'text/plain';
* $params['encoding'] = '7bit';
* $text = $email->addSubPart($body, $params);
*
* // Now add an attachment. Assume $attach is
* the contents of the attachment
*
* $params['content_type'] = 'application/zip';
* $params['encoding'] = 'base64';
* $params['disposition'] = 'attachment';
* $params['dfilename'] = 'example.zip';
* $attach =& $email->addSubPart($body, $params);
*
* // Now build the email. Note that the encode
* // function returns an associative array containing two
* // elements, body and headers. You will need to add extra
* // headers, (eg. Mime-Version) before sending.
*
* $email = $message->encode();
* $email['headers'][] = 'Mime-Version: 1.0';
*
*
* Further examples are available at http://www.phpguru.org
*
* TODO:
* - Set encode() to return the $obj->encoded if encode()
* has already been run. Unless a flag is passed to specifically
* re-build the message.
*
* @author Richard Heyes <richard@phpguru.org>
* @version $Revision: 1.3 $
* @package Mail
*/
class Mail_mimePart {
/**
* The encoding type of this part
* @var string
*/
var $_encoding;
/**
* An array of subparts
* @var array
*/
var $_subparts;
/**
* The output of this part after being built
* @var string
*/
var $_encoded;
/**
* Headers for this part
* @var array
*/
var $_headers;
/**
* The body of this part (not encoded)
* @var string
*/
var $_body;
/**
* Constructor.
*
* Sets up the object.
*
* @param $body - The body of the mime part if any.
* @param $params - An associative array of parameters:
* content_type - The content type for this part eg multipart/mixed
* encoding - The encoding to use, 7bit, 8bit, base64, or quoted-printable
* cid - Content ID to apply
* disposition - Content disposition, inline or attachment
* dfilename - Optional filename parameter for content disposition
* description - Content description
* charset - Character set to use
* @access public
*/
function Mail_mimePart($body = '', $params = array())
{
if (!defined('MAIL_MIMEPART_CRLF')) {
define('MAIL_MIMEPART_CRLF', defined('MAIL_MIME_CRLF') ? MAIL_MIME_CRLF : "\r\n", TRUE);
}
foreach ($params as $key => $value) {
switch ($key) {
case 'content_type':
$headers['Content-Type'] = $value . (isset($charset) ? '; charset="' . $charset . '"' : '');
break;
case 'encoding':
$this->_encoding = $value;
$headers['Content-Transfer-Encoding'] = $value;
break;
case 'cid':
$headers['Content-ID'] = '<' . $value . '>';
break;
case 'disposition':
$headers['Content-Disposition'] = $value . (isset($dfilename) ? '; filename="' . $dfilename . '"' : '');
break;
case 'dfilename':
if (isset($headers['Content-Disposition'])) {
$headers['Content-Disposition'] .= '; filename="' . $value . '"';
} else {
$dfilename = $value;
}
break;
case 'description':
$headers['Content-Description'] = $value;
break;
case 'charset':
if (isset($headers['Content-Type'])) {
$headers['Content-Type'] .= '; charset="' . $value . '"';
} else {
$charset = $value;
}
break;
}
}
// Default content-type
if (!isset($headers['Content-Type'])) {
$headers['Content-Type'] = 'text/plain';
}
//Default encoding
if (!isset($this->_encoding)) {
$this->_encoding = '7bit';
}
// Assign stuff to member variables
$this->_encoded = array();
$this->_headers = $headers;
$this->_body = $body;
}
/**
* encode()
*
* Encodes and returns the email. Also stores
* it in the encoded member variable
*
* @return An associative array containing two elements,
* body and headers. The headers element is itself
* an indexed array.
* @access public
*/
function encode()
{
$encoded =& $this->_encoded;
if (!empty($this->_subparts)) {
srand((double)microtime()*1000000);
$boundary = '=_' . md5(uniqid(rand()) . microtime());
$this->_headers['Content-Type'] .= ';' . MAIL_MIMEPART_CRLF . "\t" . 'boundary="' . $boundary . '"';
// Add body parts to $subparts
for ($i = 0; $i < count($this->_subparts); $i++) {
$headers = array();
$tmp = $this->_subparts[$i]->encode();
foreach ($tmp['headers'] as $key => $value) {
$headers[] = $key . ': ' . $value;
}
$subparts[] = implode(MAIL_MIMEPART_CRLF, $headers) . MAIL_MIMEPART_CRLF . MAIL_MIMEPART_CRLF . $tmp['body'];
}
$encoded['body'] = '--' . $boundary . MAIL_MIMEPART_CRLF .
implode('--' . $boundary . MAIL_MIMEPART_CRLF, $subparts) .
'--' . $boundary.'--' . MAIL_MIMEPART_CRLF;
} else {
$encoded['body'] = $this->_getEncodedData($this->_body, $this->_encoding) . MAIL_MIMEPART_CRLF;
}
// Add headers to $encoded
$encoded['headers'] =& $this->_headers;
return $encoded;
}
/**
* &addSubPart()
*
* Adds a subpart to current mime part and returns
* a reference to it
*
* @param $body The body of the subpart, if any.
* @param $params The parameters for the subpart, same
* as the $params argument for constructor.
* @return A reference to the part you just added. It is
* crucial if using multipart/* in your subparts that
* you use =& in your script when calling this function,
* otherwise you will not be able to add further subparts.
* @access public
*/
function &addSubPart($body, $params)
{
$this->_subparts[] = new Mail_mimePart($body, $params);
return $this->_subparts[count($this->_subparts) - 1];
}
/**
* _getEncodedData()
*
* Returns encoded data based upon encoding passed to it
*
* @param $data The data to encode.
* @param $encoding The encoding type to use, 7bit, base64,
* or quoted-printable.
* @access private
*/
function _getEncodedData($data, $encoding)
{
switch ($encoding) {
case '8bit':
case '7bit':
return $data;
break;
case 'quoted-printable':
return $this->_quotedPrintableEncode($data);
break;
case 'base64':
return rtrim(chunk_split(base64_encode($data), 76, MAIL_MIMEPART_CRLF));
break;
default:
return $data;
}
}
/**
* quoteadPrintableEncode()
*
* Encodes data to quoted-printable standard.
*
* @param $input The data to encode
* @param $line_max Optional max line length. Should
* not be more than 76 chars
*
* @access private
*/
function _quotedPrintableEncode($input , $line_max = 76)
{
$lines = preg_split("/\r?\n/", $input);
$eol = MAIL_MIMEPART_CRLF;
$escape = '=';
$output = '';
while(list(, $line) = each($lines)){
$linlen = strlen($line);
$newline = '';
for ($i = 0; $i < $linlen; $i++) {
$char = substr($line, $i, 1);
$dec = ord($char);
if (($dec == 32) AND ($i == ($linlen - 1))){ // convert space at eol only
$char = '=20';
} elseif($dec == 9) {
; // Do nothing if a tab.
} elseif(($dec == 61) OR ($dec < 32 ) OR ($dec > 126)) {
$char = $escape . strtoupper(sprintf('%02s', dechex($dec)));
}
if ((strlen($newline) + strlen($char)) >= $line_max) { // MAIL_MIMEPART_CRLF is not counted
$output .= $newline . $escape . $eol; // soft line break; " =\r\n" is okay
$newline = '';
}
$newline .= $char;
} // end of for
$output .= $newline . $eol;
}
$output = substr($output, 0, -1 * strlen($eol)); // Don't want last crlf
return $output;
}
} // End of class
?>

View File

@@ -0,0 +1,359 @@
<?php
/**
* Filename.......: class.smtp.inc
* Project........: SMTP Class
* Version........: 1.0.5
* Last Modified..: 21 December 2001
*/
define('SMTP_STATUS_NOT_CONNECTED', 1, TRUE);
define('SMTP_STATUS_CONNECTED', 2, TRUE);
class smtp{
var $authenticated;
var $connection;
var $recipients;
var $headers;
var $timeout;
var $errors;
var $status;
var $body;
var $from;
var $host;
var $port;
var $helo;
var $auth;
var $user;
var $pass;
/**
* Constructor function. Arguments:
* $params - An assoc array of parameters:
*
* host - The hostname of the smtp server Default: localhost
* port - The port the smtp server runs on Default: 25
* helo - What to send as the HELO command Default: localhost
* (typically the hostname of the
* machine this script runs on)
* auth - Whether to use basic authentication Default: FALSE
* user - Username for authentication Default: <blank>
* pass - Password for authentication Default: <blank>
* timeout - The timeout in seconds for the call Default: 5
* to fsockopen()
*/
function smtp($params = array()){
if(!defined('CRLF'))
define('CRLF', "\r\n", TRUE);
$this->authenticated = FALSE;
$this->timeout = 5;
$this->status = SMTP_STATUS_NOT_CONNECTED;
$this->host = 'localhost';
$this->port = 25;
$this->helo = 'localhost';
$this->auth = FALSE;
$this->user = '';
$this->pass = '';
$this->errors = array();
foreach($params as $key => $value){
$this->$key = $value;
}
}
/**
* Connect function. This will, when called
* statically, create a new smtp object,
* call the connect function (ie this function)
* and return it. When not called statically,
* it will connect to the server and send
* the HELO command.
*/
function &connect($params = array()){
if(!isset($this->status)){
$obj = new smtp($params);
if($obj->connect()){
$obj->status = SMTP_STATUS_CONNECTED;
}
return $obj;
}else{
$this->connection = fsockopen($this->host, $this->port, $errno, $errstr, $this->timeout);
if(function_exists('socket_set_timeout')){
@socket_set_timeout($this->connection, 5, 0);
}
$greeting = $this->get_data();
if(is_resource($this->connection)){
return $this->auth ? $this->ehlo() : $this->helo();
}else{
$this->errors[] = 'Failed to connect to server: '.$errstr;
return FALSE;
}
}
}
/**
* Function which handles sending the mail.
* Arguments:
* $params - Optional assoc array of parameters.
* Can contain:
* recipients - Indexed array of recipients
* from - The from address. (used in MAIL FROM:),
* this will be the return path
* headers - Indexed array of headers, one header per array entry
* body - The body of the email
* It can also contain any of the parameters from the connect()
* function
*/
function send($params = array()){
foreach($params as $key => $value){
$this->set($key, $value);
}
if($this->is_connected()){
// Do we auth or not? Note the distinction between the auth variable and auth() function
if($this->auth AND !$this->authenticated){
if(!$this->auth())
return FALSE;
}
$this->mail($this->from);
if(is_array($this->recipients))
foreach($this->recipients as $value)
$this->rcpt($value);
else
$this->rcpt($this->recipients);
if(!$this->data())
return FALSE;
// Transparency
$headers = str_replace(CRLF.'.', CRLF.'..', trim(implode(CRLF, $this->headers)));
$body = str_replace(CRLF.'.', CRLF.'..', $this->body);
$body = $body[0] == '.' ? '.'.$body : $body;
$this->send_data($headers);
$this->send_data('');
$this->send_data($body);
$this->send_data('.');
$result = (substr(trim($this->get_data()), 0, 3) === '250');
//$this->rset();
return $result;
}else{
$this->errors[] = 'Not connected!';
return FALSE;
}
}
/**
* Function to implement HELO cmd
*/
function helo(){
if(is_resource($this->connection)
AND $this->send_data('HELO '.$this->helo)
AND substr(trim($error = $this->get_data()), 0, 3) === '250' ){
return TRUE;
}else{
$this->errors[] = 'HELO command failed, output: ' . trim(substr(trim($error),3));
return FALSE;
}
}
/**
* Function to implement EHLO cmd
*/
function ehlo(){
if(is_resource($this->connection)
AND $this->send_data('EHLO '.$this->helo)
AND substr(trim($error = $this->get_data()), 0, 3) === '250' ){
return TRUE;
}else{
$this->errors[] = 'EHLO command failed, output: ' . trim(substr(trim($error),3));
return FALSE;
}
}
/**
* Function to implement RSET cmd
*/
function rset(){
if(is_resource($this->connection)
AND $this->send_data('RSET')
AND substr(trim($error = $this->get_data()), 0, 3) === '250' ){
return TRUE;
}else{
$this->errors[] = 'RSET command failed, output: ' . trim(substr(trim($error),3));
return FALSE;
}
}
/**
* Function to implement QUIT cmd
*/
function quit(){
if(is_resource($this->connection)
AND $this->send_data('QUIT')
AND substr(trim($error = $this->get_data()), 0, 3) === '221' ){
fclose($this->connection);
$this->status = SMTP_STATUS_NOT_CONNECTED;
return TRUE;
}else{
$this->errors[] = 'QUIT command failed, output: ' . trim(substr(trim($error),3));
return FALSE;
}
}
/**
* Function to implement AUTH cmd
*/
function auth(){
if(is_resource($this->connection)
AND $this->send_data('AUTH LOGIN')
AND substr(trim($error = $this->get_data()), 0, 3) === '334'
AND $this->send_data(base64_encode($this->user)) // Send username
AND substr(trim($error = $this->get_data()),0,3) === '334'
AND $this->send_data(base64_encode($this->pass)) // Send password
AND substr(trim($error = $this->get_data()),0,3) === '235' ){
$this->authenticated = TRUE;
return TRUE;
}else{
$this->errors[] = 'AUTH command failed: ' . trim(substr(trim($error),3));
return FALSE;
}
}
/**
* Function that handles the MAIL FROM: cmd
*/
function mail($from){
if($this->is_connected()
AND $this->send_data('MAIL FROM:<'.$from.'>')
AND substr(trim($this->get_data()), 0, 2) === '250' ){
return TRUE;
}else
return FALSE;
}
/**
* Function that handles the RCPT TO: cmd
*/
function rcpt($to){
if($this->is_connected()
AND $this->send_data('RCPT TO:<'.$to.'>')
AND substr(trim($error = $this->get_data()), 0, 2) === '25' ){
return TRUE;
}else{
$this->errors[] = trim(substr(trim($error), 3));
return FALSE;
}
}
/**
* Function that sends the DATA cmd
*/
function data(){
if($this->is_connected()
AND $this->send_data('DATA')
AND substr(trim($error = $this->get_data()), 0, 3) === '354' ){
return TRUE;
}else{
$this->errors[] = trim(substr(trim($error), 3));
return FALSE;
}
}
/**
* Function to determine if this object
* is connected to the server or not.
*/
function is_connected(){
return (is_resource($this->connection) AND ($this->status === SMTP_STATUS_CONNECTED));
}
/**
* Function to send a bit of data
*/
function send_data($data){
if(is_resource($this->connection)){
return fwrite($this->connection, $data.CRLF, strlen($data)+2);
}else
return FALSE;
}
/**
* Function to get data.
*/
function &get_data(){
$return = '';
$line = '';
$loops = 0;
if(is_resource($this->connection)){
while((strpos($return, CRLF) === FALSE OR substr($line,3,1) !== ' ') AND $loops < 100){
$line = fgets($this->connection, 512);
$return .= $line;
$loops++;
}
return $return;
}else
return FALSE;
}
/**
* Sets a variable
*/
function set($var, $value){
$this->$var = $value;
return TRUE;
}
} // End of class
?>

View File

@@ -0,0 +1,3 @@
<?php
die("Access Denied");
?>

View File

@@ -0,0 +1,900 @@
<?php
/*************************************************
Snoopy - the PHP net client
Author: Monte Ohrt <monte@ispi.net>
Copyright (c): 1999-2000 ispi, all rights reserved
Version: 1.0
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
You may contact the author of Snoopy by e-mail at:
monte@ispi.net
Or, write to:
Monte Ohrt
CTO, ispi
237 S. 70th suite 220
Lincoln, NE 68510
The latest version of Snoopy can be obtained from:
http://snoopy.sourceforge.com
*************************************************/
class Snoopy
{
/**** Public variables ****/
/* user definable vars */
var $host = "www.php.net"; // host name we are connecting to
var $port = 80; // port we are connecting to
var $proxy_host = ""; // proxy host to use
var $proxy_port = ""; // proxy port to use
var $agent = "Snoopy v1.0"; // agent we masquerade as
var $referer = ""; // referer info to pass
var $cookies = array(); // array of cookies to pass
// $cookies["username"]="joe";
var $rawheaders = array(); // array of raw headers to send
// $rawheaders["Content-type"]="text/html";
var $maxredirs = 5; // http redirection depth maximum. 0 = disallow
var $lastredirectaddr = ""; // contains address of last redirected address
var $offsiteok = true; // allows redirection off-site
var $maxframes = 0; // frame content depth maximum. 0 = disallow
var $expandlinks = true; // expand links to fully qualified URLs.
// this only applies to fetchlinks()
// or submitlinks()
var $passcookies = true; // pass set cookies back through redirects
// NOTE: this currently does not respect
// dates, domains or paths.
var $user = ""; // user for http authentication
var $pass = ""; // password for http authentication
// http accept types
var $accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*";
var $results = ""; // where the content is put
var $error = ""; // error messages sent here
var $response_code = ""; // response code returned from server
var $headers = array(); // headers returned from server sent here
var $maxlength = 500000; // max return data length (body)
var $read_timeout = 0; // timeout on read operations, in seconds
// supported only since PHP 4 Beta 4
// set to 0 to disallow timeouts
var $timed_out = false; // if a read operation timed out
var $status = 0; // http request status
var $curl_path = "/usr/bin/curl";
// Snoopy will use cURL for fetching
// SSL content if a full system path to
// the cURL binary is supplied here.
// set to false if you do not have
// cURL installed. See http://curl.haxx.se
// for details on installing cURL.
// Snoopy does *not* use the cURL
// library functions built into php,
// as these functions are not stable
// as of this Snoopy release.
// send Accept-encoding: gzip?
var $use_gzip = true;
/**** Private variables ****/
var $_maxlinelen = 4096; // max line length (headers)
var $_httpmethod = "GET"; // default http request method
var $_httpversion = "HTTP/1.0"; // default http request version
var $_submit_method = "POST"; // default submit method
var $_submit_type = "application/x-www-form-urlencoded"; // default submit type
var $_mime_boundary = ""; // MIME boundary for multipart/form-data submit type
var $_redirectaddr = false; // will be set if page fetched is a redirect
var $_redirectdepth = 0; // increments on an http redirect
var $_frameurls = array(); // frame src urls
var $_framedepth = 0; // increments on frame depth
var $_isproxy = false; // set if using a proxy server
var $_fp_timeout = 30; // timeout for socket connection
/*======================================================================*\
Function: fetch
Purpose: fetch the contents of a web page
(and possibly other protocols in the
future like ftp, nntp, gopher, etc.)
Input: $URI the location of the page to fetch
Output: $this->results the output text from the fetch
\*======================================================================*/
function fetch($URI)
{
//preg_match("|^([^:]+)://([^:/]+)(:[\d]+)*(.*)|",$URI,$URI_PARTS);
$URI_PARTS = parse_url($URI);
if (!empty($URI_PARTS["user"]))
$this->user = $URI_PARTS["user"];
if (!empty($URI_PARTS["pass"]))
$this->pass = $URI_PARTS["pass"];
switch($URI_PARTS["scheme"])
{
case "http":
$this->host = $URI_PARTS["host"];
if(!empty($URI_PARTS["port"]))
$this->port = $URI_PARTS["port"];
if($this->_connect($fp))
{
if($this->_isproxy)
{
// using proxy, send entire URI
$this->_httprequest($URI,$fp,$URI,$this->_httpmethod);
}
else
{
$path = $URI_PARTS["path"].(isset($URI_PARTS["query"]) ? "?".$URI_PARTS["query"] : "");
// no proxy, send only the path
$this->_httprequest($path, $fp, $URI, $this->_httpmethod);
}
$this->_disconnect($fp);
if($this->_redirectaddr)
{
/* url was redirected, check if we've hit the max depth */
if($this->maxredirs > $this->_redirectdepth)
{
// only follow redirect if it's on this site, or offsiteok is true
if(preg_match("|^http://".preg_quote($this->host)."|i",$this->_redirectaddr) || $this->offsiteok)
{
/* follow the redirect */
$this->_redirectdepth++;
$this->lastredirectaddr=$this->_redirectaddr;
$this->fetch($this->_redirectaddr);
}
}
}
if($this->_framedepth < $this->maxframes && count($this->_frameurls) > 0)
{
$frameurls = $this->_frameurls;
$this->_frameurls = array();
while(list(,$frameurl) = each($frameurls))
{
if($this->_framedepth < $this->maxframes)
{
$this->fetch($frameurl);
$this->_framedepth++;
}
else
break;
}
}
}
else
{
return false;
}
return true;
break;
case "https":
if(!$this->curl_path || (!is_executable($this->curl_path))) {
$this->error = "Bad curl ($this->curl_path), can't fetch HTTPS \n";
return false;
}
$this->host = $URI_PARTS["host"];
if(!empty($URI_PARTS["port"]))
$this->port = $URI_PARTS["port"];
if($this->_isproxy)
{
// using proxy, send entire URI
$this->_httpsrequest($URI,$URI,$this->_httpmethod);
}
else
{
$path = $URI_PARTS["path"].($URI_PARTS["query"] ? "?".$URI_PARTS["query"] : "");
// no proxy, send only the path
$this->_httpsrequest($path, $URI, $this->_httpmethod);
}
if($this->_redirectaddr)
{
/* url was redirected, check if we've hit the max depth */
if($this->maxredirs > $this->_redirectdepth)
{
// only follow redirect if it's on this site, or offsiteok is true
if(preg_match("|^http://".preg_quote($this->host)."|i",$this->_redirectaddr) || $this->offsiteok)
{
/* follow the redirect */
$this->_redirectdepth++;
$this->lastredirectaddr=$this->_redirectaddr;
$this->fetch($this->_redirectaddr);
}
}
}
if($this->_framedepth < $this->maxframes && count($this->_frameurls) > 0)
{
$frameurls = $this->_frameurls;
$this->_frameurls = array();
while(list(,$frameurl) = each($frameurls))
{
if($this->_framedepth < $this->maxframes)
{
$this->fetch($frameurl);
$this->_framedepth++;
}
else
break;
}
}
return true;
break;
default:
// not a valid protocol
$this->error = 'Invalid protocol "'.$URI_PARTS["scheme"].'"\n';
return false;
break;
}
return true;
}
/*======================================================================*\
Private functions
\*======================================================================*/
/*======================================================================*\
Function: _striplinks
Purpose: strip the hyperlinks from an html document
Input: $document document to strip.
Output: $match an array of the links
\*======================================================================*/
function _striplinks($document)
{
preg_match_all("'<\s*a\s+.*href\s*=\s* # find <a href=
([\"\'])? # find single or double quote
(?(1) (.*?)\\1 | ([^\s\>]+)) # if quote found, match up to next matching
# quote, otherwise match up to next space
'isx",$document,$links);
// catenate the non-empty matches from the conditional subpattern
while(list($key,$val) = each($links[2]))
{
if(!empty($val))
$match[] = $val;
}
while(list($key,$val) = each($links[3]))
{
if(!empty($val))
$match[] = $val;
}
// return the links
return $match;
}
/*======================================================================*\
Function: _stripform
Purpose: strip the form elements from an html document
Input: $document document to strip.
Output: $match an array of the links
\*======================================================================*/
function _stripform($document)
{
preg_match_all("'<\/?(FORM|INPUT|SELECT|TEXTAREA|(OPTION))[^<>]*>(?(2)(.*(?=<\/?(option|select)[^<>]*>[\r\n]*)|(?=[\r\n]*))|(?=[\r\n]*))'Usi",$document,$elements);
// catenate the matches
$match = implode("\r\n",$elements[0]);
// return the links
return $match;
}
/*======================================================================*\
Function: _striptext
Purpose: strip the text from an html document
Input: $document document to strip.
Output: $text the resulting text
\*======================================================================*/
function _striptext($document)
{
// I didn't use preg eval (//e) since that is only available in PHP 4.0.
// so, list your entities one by one here. I included some of the
// more common ones.
$search = array("'<script[^>]*?>.*?</script>'si", // strip out javascript
"'<[\/\!]*?[^<>]*?>'si", // strip out html tags
"'([\r\n])[\s]+'", // strip out white space
"'&(quote|#34);'i", // replace html entities
"'&(amp|#38);'i",
"'&(lt|#60);'i",
"'&(gt|#62);'i",
"'&(nbsp|#160);'i",
"'&(iexcl|#161);'i",
"'&(cent|#162);'i",
"'&(pound|#163);'i",
"'&(copy|#169);'i"
);
$replace = array( "",
"",
"\\1",
"\"",
"&",
"<",
">",
" ",
chr(161),
chr(162),
chr(163),
chr(169));
$text = preg_replace($search,$replace,$document);
return $text;
}
/*======================================================================*\
Function: _expandlinks
Purpose: expand each link into a fully qualified URL
Input: $links the links to qualify
$URI the full URI to get the base from
Output: $expandedLinks the expanded links
\*======================================================================*/
function _expandlinks($links,$URI)
{
preg_match("/^[^\?]+/",$URI,$match);
$match = preg_replace("|/[^\/\.]+\.[^\/\.]+$|","",$match[0]);
$search = array( "|^http://".preg_quote($this->host)."|i",
"|^(?!http://)(\/)?(?!mailto:)|i",
"|/\./|",
"|/[^\/]+/\.\./|"
);
$replace = array( "",
$match."/",
"/",
"/"
);
$expandedLinks = preg_replace($search,$replace,$links);
return $expandedLinks;
}
/*======================================================================*\
Function: _httprequest
Purpose: go get the http data from the server
Input: $url the url to fetch
$fp the current open file pointer
$URI the full URI
$body body contents to send if any (POST)
Output:
\*======================================================================*/
function _httprequest($url,$fp,$URI,$http_method,$content_type="",$body="")
{
if($this->passcookies && $this->_redirectaddr)
$this->setcookies();
$URI_PARTS = parse_url($URI);
if(empty($url))
$url = "/";
$headers = $http_method." ".$url." ".$this->_httpversion."\r\n";
if(!empty($this->agent))
$headers .= "User-Agent: ".$this->agent."\r\n";
if(!empty($this->host) && !isset($this->rawheaders['Host']))
$headers .= "Host: ".$this->host."\r\n";
if(!empty($this->accept))
$headers .= "Accept: ".$this->accept."\r\n";
if($this->use_gzip) {
// make sure PHP was built with --with-zlib
// and we can handle gzipp'ed data
if ( function_exists(gzinflate) ) {
$headers .= "Accept-encoding: gzip\r\n";
}
else {
trigger_error(
"use_gzip is on, but PHP was built without zlib support.".
" Requesting file(s) without gzip encoding.",
E_USER_NOTICE);
}
}
if(!empty($this->referer))
$headers .= "Referer: ".$this->referer."\r\n";
if(!empty($this->cookies))
{
if(!is_array($this->cookies))
$this->cookies = (array)$this->cookies;
reset($this->cookies);
if ( count($this->cookies) > 0 ) {
$cookie_headers .= 'Cookie: ';
foreach ( $this->cookies as $cookieKey => $cookieVal ) {
$cookie_headers .= $cookieKey."=".urlencode($cookieVal)."; ";
}
$headers .= substr($cookie_headers,0,-2) . "\r\n";
}
}
if(!empty($this->rawheaders))
{
if(!is_array($this->rawheaders))
$this->rawheaders = (array)$this->rawheaders;
while(list($headerKey,$headerVal) = each($this->rawheaders))
$headers .= $headerKey.": ".$headerVal."\r\n";
}
if(!empty($content_type)) {
$headers .= "Content-type: $content_type";
if ($content_type == "multipart/form-data")
$headers .= "; boundary=".$this->_mime_boundary;
$headers .= "\r\n";
}
if(!empty($body))
$headers .= "Content-length: ".strlen($body)."\r\n";
if(!empty($this->user) || !empty($this->pass))
$headers .= "Authorization: BASIC ".base64_encode($this->user.":".$this->pass)."\r\n";
$headers .= "\r\n";
// set the read timeout if needed
if ($this->read_timeout > 0)
socket_set_timeout($fp, $this->read_timeout);
$this->timed_out = false;
fwrite($fp,$headers.$body,strlen($headers.$body));
$this->_redirectaddr = false;
unset($this->headers);
// content was returned gzip encoded?
$is_gzipped = false;
while($currentHeader = fgets($fp,$this->_maxlinelen))
{
if ($this->read_timeout > 0 && $this->_check_timeout($fp))
{
$this->status=-100;
return false;
}
// if($currentHeader == "\r\n")
if(preg_match("/^\r?\n$/", $currentHeader) )
break;
// if a header begins with Location: or URI:, set the redirect
if(preg_match("/^(Location:|URI:)/i",$currentHeader))
{
// get URL portion of the redirect
preg_match("/^(Location:|URI:)\s+(.*)/",chop($currentHeader),$matches);
// look for :// in the Location header to see if hostname is included
if(!preg_match("|\:\/\/|",$matches[2]))
{
// no host in the path, so prepend
$this->_redirectaddr = $URI_PARTS["scheme"]."://".$this->host.":".$this->port;
// eliminate double slash
if(!preg_match("|^/|",$matches[2]))
$this->_redirectaddr .= "/".$matches[2];
else
$this->_redirectaddr .= $matches[2];
}
else
$this->_redirectaddr = $matches[2];
}
if(preg_match("|^HTTP/|",$currentHeader))
{
if(preg_match("|^HTTP/[^\s]*\s(.*?)\s|",$currentHeader, $status))
{
$this->status= $status[1];
}
$this->response_code = $currentHeader;
}
if (preg_match("/Content-Encoding: gzip/", $currentHeader) ) {
$is_gzipped = true;
}
$this->headers[] = $currentHeader;
}
# $results = fread($fp, $this->maxlength);
$results = "";
while ( $data = fread($fp, $this->maxlength) ) {
$results .= $data;
if (
strlen($results) > $this->maxlength ) {
break;
}
}
// gunzip
if ( $is_gzipped ) {
// per http://www.php.net/manual/en/function.gzencode.php
$results = substr($results, 10);
$results = gzinflate($results);
}
if ($this->read_timeout > 0 && $this->_check_timeout($fp))
{
$this->status=-100;
return false;
}
// check if there is a a redirect meta tag
if(preg_match("'<meta[\s]*http-equiv[^>]*?content[\s]*=[\s]*[\"\']?\d+;[\s]+URL[\s]*=[\s]*([^\"\']*?)[\"\']?>'i",$results,$match))
{
$this->_redirectaddr = $this->_expandlinks($match[1],$URI);
}
// have we hit our frame depth and is there frame src to fetch?
if(($this->_framedepth < $this->maxframes) && preg_match_all("'<frame\s+.*src[\s]*=[\'\"]?([^\'\"\>]+)'i",$results,$match))
{
$this->results[] = $results;
for($x=0; $x<count($match[1]); $x++)
$this->_frameurls[] = $this->_expandlinks($match[1][$x],$URI_PARTS["scheme"]."://".$this->host);
}
// have we already fetched framed content?
elseif(is_array($this->results))
$this->results[] = $results;
// no framed content
else
$this->results = $results;
return true;
}
/*======================================================================*\
Function: _httpsrequest
Purpose: go get the https data from the server using curl
Input: $url the url to fetch
$URI the full URI
$body body contents to send if any (POST)
Output:
\*======================================================================*/
function _httpsrequest($url,$URI,$http_method,$content_type="",$body="")
{
if($this->passcookies && $this->_redirectaddr)
$this->setcookies();
$headers = array();
$URI_PARTS = parse_url($URI);
if(empty($url))
$url = "/";
// GET ... header not needed for curl
//$headers[] = $http_method." ".$url." ".$this->_httpversion;
if(!empty($this->agent))
$headers[] = "User-Agent: ".$this->agent;
if(!empty($this->host))
$headers[] = "Host: ".$this->host;
if(!empty($this->accept))
$headers[] = "Accept: ".$this->accept;
if(!empty($this->referer))
$headers[] = "Referer: ".$this->referer;
if(!empty($this->cookies))
{
if(!is_array($this->cookies))
$this->cookies = (array)$this->cookies;
reset($this->cookies);
if ( count($this->cookies) > 0 ) {
$cookie_str = 'Cookie: ';
foreach ( $this->cookies as $cookieKey => $cookieVal ) {
$cookie_str .= $cookieKey."=".urlencode($cookieVal)."; ";
}
$headers[] = substr($cookie_str,0,-2);
}
}
if(!empty($this->rawheaders))
{
if(!is_array($this->rawheaders))
$this->rawheaders = (array)$this->rawheaders;
while(list($headerKey,$headerVal) = each($this->rawheaders))
$headers[] = $headerKey.": ".$headerVal;
}
if(!empty($content_type)) {
if ($content_type == "multipart/form-data")
$headers[] = "Content-type: $content_type; boundary=".$this->_mime_boundary;
else
$headers[] = "Content-type: $content_type";
}
if(!empty($body))
$headers[] = "Content-length: ".strlen($body);
if(!empty($this->user) || !empty($this->pass))
$headers[] = "Authorization: BASIC ".base64_encode($this->user.":".$this->pass);
for($curr_header = 0; $curr_header < count($headers); $curr_header++) {
$cmdline_params .= " -H \"".$headers[$curr_header]."\"";
}
if(!empty($body))
$cmdline_params .= " -d \"$body\"";
if($this->read_timeout > 0)
$cmdline_params .= " -m ".$this->read_timeout;
$headerfile = uniqid(time());
# accept self-signed certs
$cmdline_params .= " -k";
exec($this->curl_path." -D \"/tmp/$headerfile\"".escapeshellcmd($cmdline_params)." ".escapeshellcmd($URI),$results,$return);
if($return)
{
$this->error = "Error: cURL could not retrieve the document, error $return.";
return false;
}
$results = implode("\r\n",$results);
$result_headers = file("/tmp/$headerfile");
$this->_redirectaddr = false;
unset($this->headers);
for($currentHeader = 0; $currentHeader < count($result_headers); $currentHeader++)
{
// if a header begins with Location: or URI:, set the redirect
if(preg_match("/^(Location: |URI: )/i",$result_headers[$currentHeader]))
{
// get URL portion of the redirect
preg_match("/^(Location: |URI:)(.*)/",chop($result_headers[$currentHeader]),$matches);
// look for :// in the Location header to see if hostname is included
if(!preg_match("|\:\/\/|",$matches[2]))
{
// no host in the path, so prepend
$this->_redirectaddr = $URI_PARTS["scheme"]."://".$this->host.":".$this->port;
// eliminate double slash
if(!preg_match("|^/|",$matches[2]))
$this->_redirectaddr .= "/".$matches[2];
else
$this->_redirectaddr .= $matches[2];
}
else
$this->_redirectaddr = $matches[2];
}
if(preg_match("|^HTTP/|",$result_headers[$currentHeader]))
{
$this->response_code = $result_headers[$currentHeader];
if(preg_match("|^HTTP/[^\s]*\s(.*?)\s|",$this->response_code, $match))
{
$this->status= $match[1];
}
}
$this->headers[] = $result_headers[$currentHeader];
}
// check if there is a a redirect meta tag
if(preg_match("'<meta[\s]*http-equiv[^>]*?content[\s]*=[\s]*[\"\']?\d+;[\s]+URL[\s]*=[\s]*([^\"\']*?)[\"\']?>'i",$results,$match))
{
$this->_redirectaddr = $this->_expandlinks($match[1],$URI);
}
// have we hit our frame depth and is there frame src to fetch?
if(($this->_framedepth < $this->maxframes) && preg_match_all("'<frame\s+.*src[\s]*=[\'\"]?([^\'\"\>]+)'i",$results,$match))
{
$this->results[] = $results;
for($x=0; $x<count($match[1]); $x++)
$this->_frameurls[] = $this->_expandlinks($match[1][$x],$URI_PARTS["scheme"]."://".$this->host);
}
// have we already fetched framed content?
elseif(is_array($this->results))
$this->results[] = $results;
// no framed content
else
$this->results = $results;
unlink("/tmp/$headerfile");
return true;
}
/*======================================================================*\
Function: setcookies()
Purpose: set cookies for a redirection
\*======================================================================*/
function setcookies()
{
for($x=0; $x<count($this->headers); $x++)
{
if(preg_match("/^set-cookie:[\s]+([^=]+)=([^;]+)/i", $this->headers[$x],$match))
$this->cookies[$match[1]] = $match[2];
}
}
/*======================================================================*\
Function: _check_timeout
Purpose: checks whether timeout has occurred
Input: $fp file pointer
\*======================================================================*/
function _check_timeout($fp)
{
if ($this->read_timeout > 0) {
$fp_status = socket_get_status($fp);
if ($fp_status["timed_out"]) {
$this->timed_out = true;
return true;
}
}
return false;
}
/*======================================================================*\
Function: _connect
Purpose: make a socket connection
Input: $fp file pointer
\*======================================================================*/
function _connect(&$fp)
{
if(!empty($this->proxy_host) && !empty($this->proxy_port))
{
$this->_isproxy = true;
$host = $this->proxy_host;
$port = $this->proxy_port;
}
else
{
$host = $this->host;
$port = $this->port;
}
$this->status = 0;
if($fp = fsockopen(
$host,
$port,
$errno,
$errstr,
$this->_fp_timeout
))
{
// socket connection succeeded
return true;
}
else
{
// socket connection failed
$this->status = $errno;
switch($errno)
{
case -3:
$this->error="socket creation failed (-3)";
case -4:
$this->error="dns lookup failure (-4)";
case -5:
$this->error="connection refused or timed out (-5)";
default:
$this->error="connection failed (".$errno.")";
}
return false;
}
}
/*======================================================================*\
Function: _disconnect
Purpose: disconnect a socket connection
Input: $fp file pointer
\*======================================================================*/
function _disconnect($fp)
{
return(fclose($fp));
}
/*======================================================================*\
Function: _prepare_post_body
Purpose: Prepare post body according to encoding type
Input: $formvars - form variables
$formfiles - form upload files
Output: post body
\*======================================================================*/
function _prepare_post_body($formvars, $formfiles)
{
settype($formvars, "array");
settype($formfiles, "array");
if (count($formvars) == 0 && count($formfiles) == 0)
return;
switch ($this->_submit_type) {
case "application/x-www-form-urlencoded":
reset($formvars);
while(list($key,$val) = each($formvars)) {
if (is_array($val) || is_object($val)) {
while (list($cur_key, $cur_val) = each($val)) {
$postdata .= urlencode($key)."[]=".urlencode($cur_val)."&";
}
} else
$postdata .= urlencode($key)."=".urlencode($val)."&";
}
break;
case "multipart/form-data":
$this->_mime_boundary = "Snoopy".md5(uniqid(microtime()));
reset($formvars);
while(list($key,$val) = each($formvars)) {
if (is_array($val) || is_object($val)) {
while (list($cur_key, $cur_val) = each($val)) {
$postdata .= "--".$this->_mime_boundary."\r\n";
$postdata .= "Content-Disposition: form-data; name=\"$key\[\]\"\r\n\r\n";
$postdata .= "$cur_val\r\n";
}
} else {
$postdata .= "--".$this->_mime_boundary."\r\n";
$postdata .= "Content-Disposition: form-data; name=\"$key\"\r\n\r\n";
$postdata .= "$val\r\n";
}
}
reset($formfiles);
while (list($field_name, $file_names) = each($formfiles)) {
settype($file_names, "array");
while (list(, $file_name) = each($file_names)) {
if (!is_readable($file_name)) continue;
$fp = fopen($file_name, "r");
$file_content = fread($fp, filesize($file_name));
fclose($fp);
$base_name = basename($file_name);
$postdata .= "--".$this->_mime_boundary."\r\n";
$postdata .= "Content-Disposition: form-data; name=\"$field_name\"; filename=\"$base_name\"\r\n\r\n";
$postdata .= "$file_content\r\n";
}
}
$postdata .= "--".$this->_mime_boundary."--\r\n";
break;
}
return $postdata;
}
}
?>

View File

@@ -0,0 +1,200 @@
<?php
/*
* Project: MagpieRSS: a simple RSS integration tool
* File: rss_cache.inc, a simple, rolling(no GC), cache
* for RSS objects, keyed on URL.
* Author: Kellan Elliott-McCrea <kellan@protest.net>
* Version: 0.51
* License: GPL
*
* The lastest version of MagpieRSS can be obtained from:
* http://magpierss.sourceforge.net
*
* For questions, help, comments, discussion, etc., please join the
* Magpie mailing list:
* http://lists.sourceforge.net/lists/listinfo/magpierss-general
*
*/
class RSSCache {
var $BASE_CACHE = './cache'; // where the cache files are stored
var $MAX_AGE = 3600; // when are files stale, default one hour
var $ERROR = ""; // accumulate error messages
function RSSCache ($base='', $age='') {
if ( $base ) {
$this->BASE_CACHE = $base;
}
if ( $age ) {
$this->MAX_AGE = $age;
}
// attempt to make the cache directory
if ( ! file_exists( $this->BASE_CACHE ) ) {
$status = @mkdir( $this->BASE_CACHE, 0755 );
// if make failed
if ( ! $status ) {
$this->error(
"Cache couldn't make dir '" . $this->BASE_CACHE . "'."
);
}
}
}
/*=======================================================================*\
Function: set
Purpose: add an item to the cache, keyed on url
Input: url from wich the rss file was fetched
Output: true on sucess
\*=======================================================================*/
function set ($url, $rss) {
$this->ERROR = "";
$cache_file = $this->file_name( $url );
$fp = @fopen( $cache_file, 'w' );
if ( ! $fp ) {
$this->error(
"Cache unable to open file for writing: $cache_file"
);
return 0;
}
$data = $this->serialize( $rss );
fwrite( $fp, $data );
fclose( $fp );
return $cache_file;
}
/*=======================================================================*\
Function: get
Purpose: fetch an item from the cache
Input: url from wich the rss file was fetched
Output: cached object on HIT, false on MISS
\*=======================================================================*/
function get ($url) {
$this->ERROR = "";
$cache_file = $this->file_name( $url );
if ( ! file_exists( $cache_file ) ) {
$this->debug(
"Cache doesn't contain: $url (cache file: $cache_file)"
);
return 0;
}
$fp = @fopen($cache_file, 'r');
if ( ! $fp ) {
$this->error(
"Failed to open cache file for reading: $cache_file"
);
return 0;
}
if ($filesize = filesize($cache_file) ) {
$data = fread( $fp, filesize($cache_file) );
$rss = $this->unserialize( $data );
return $rss;
}
return 0;
}
/*=======================================================================*\
Function: check_cache
Purpose: check a url for membership in the cache
and whether the object is older then MAX_AGE (ie. STALE)
Input: url from wich the rss file was fetched
Output: cached object on HIT, false on MISS
\*=======================================================================*/
function check_cache ( $url ) {
$this->ERROR = "";
$filename = $this->file_name( $url );
if ( file_exists( $filename ) ) {
// find how long ago the file was added to the cache
// and whether that is longer then MAX_AGE
$mtime = filemtime( $filename );
$age = time() - $mtime;
if ( $this->MAX_AGE > $age ) {
// object exists and is current
return 'HIT';
}
else {
// object exists but is old
return 'STALE';
}
}
else {
// object does not exist
return 'MISS';
}
}
function cache_age( $cache_key ) {
$filename = $this->file_name( $url );
if ( file_exists( $filename ) ) {
$mtime = filemtime( $filename );
$age = time() - $mtime;
return $age;
}
else {
return -1;
}
}
/*=======================================================================*\
Function: serialize
\*=======================================================================*/
function serialize ( $rss ) {
return serialize( $rss );
}
/*=======================================================================*\
Function: unserialize
\*=======================================================================*/
function unserialize ( $data ) {
return unserialize( $data );
}
/*=======================================================================*\
Function: file_name
Purpose: map url to location in cache
Input: url from wich the rss file was fetched
Output: a file name
\*=======================================================================*/
function file_name ($url) {
$filename = md5( $url );
return join( DIRECTORY_SEPARATOR, array( $this->BASE_CACHE, $filename ) );
}
/*=======================================================================*\
Function: error
Purpose: register error
\*=======================================================================*/
function error ($errormsg, $lvl=E_USER_WARNING) {
// append PHP's error message if track_errors enabled
if ( isset($php_errormsg) ) {
$errormsg .= " ($php_errormsg)";
}
$this->ERROR = $errormsg;
if ( MAGPIE_DEBUG ) {
trigger_error( $errormsg, $lvl);
}
else {
error_log( $errormsg, 0);
}
}
function debug ($debugmsg, $lvl=E_USER_NOTICE) {
if ( MAGPIE_DEBUG ) {
$this->error("MagpieRSS [debug] $debugmsg", $lvl);
}
}
}
?>

View File

@@ -0,0 +1,458 @@
<?php
/*
* Project: MagpieRSS: a simple RSS integration tool
* File: rss_fetch.inc, a simple functional interface
to fetching and parsing RSS files, via the
function fetch_rss()
* Author: Kellan Elliott-McCrea <kellan@protest.net>
* License: GPL
*
* The lastest version of MagpieRSS can be obtained from:
* http://magpierss.sourceforge.net
*
* For questions, help, comments, discussion, etc., please join the
* Magpie mailing list:
* magpierss-general@lists.sourceforge.net
*
*/
// Setup MAGPIE_DIR for use on hosts that don't include
// the current path in include_path.
// with thanks to rajiv and smarty
if (!defined('DIRECTORY_SEPARATOR')) {
define('DIRECTORY_SEPARATOR', DIRECTORY_SEPARATOR);
}
if (!defined('MAGPIE_DIR')) {
define('MAGPIE_DIR', dirname(__FILE__) . DIRECTORY_SEPARATOR);
}
require_once( MAGPIE_DIR . 'rss_parse.inc' );
require_once( MAGPIE_DIR . 'rss_cache.inc' );
// for including 3rd party libraries
define('MAGPIE_EXTLIB', MAGPIE_DIR . 'extlib' . DIRECTORY_SEPARATOR);
require_once( MAGPIE_EXTLIB . 'Snoopy.class.inc');
/*
* CONSTANTS - redefine these in your script to change the
* behaviour of fetch_rss() currently, most options effect the cache
*
* MAGPIE_CACHE_ON - Should Magpie cache parsed RSS objects?
* For me a built in cache was essential to creating a "PHP-like"
* feel to Magpie, see rss_cache.inc for rationale
*
*
* MAGPIE_CACHE_DIR - Where should Magpie cache parsed RSS objects?
* This should be a location that the webserver can write to. If this
* directory does not already exist Mapie will try to be smart and create
* it. This will often fail for permissions reasons.
*
*
* MAGPIE_CACHE_AGE - How long to store cached RSS objects? In seconds.
*
*
* MAGPIE_CACHE_FRESH_ONLY - If remote fetch fails, throw error
* instead of returning stale object?
*
* MAGPIE_DEBUG - Display debugging notices?
*
*/
/*=======================================================================*\
Function: fetch_rss:
Purpose: return RSS object for the give url
maintain the cache
Input: url of RSS file
Output: parsed RSS object (see rss_parse.inc)
NOTES ON CACHEING:
If caching is on (MAGPIE_CACHE_ON) fetch_rss will first check the cache.
NOTES ON RETRIEVING REMOTE FILES:
If conditional gets are on (MAGPIE_CONDITIONAL_GET_ON) fetch_rss will
return a cached object, and touch the cache object upon recieving a
304.
NOTES ON FAILED REQUESTS:
If there is an HTTP error while fetching an RSS object, the cached
version will be return, if it exists (and if MAGPIE_CACHE_FRESH_ONLY is off)
\*=======================================================================*/
define('MAGPIE_VERSION', '0.72');
$MAGPIE_ERROR = "";
function fetch_rss ($url) {
// initialize constants
init();
if ( !isset($url) ) {
error("fetch_rss called without a url");
return false;
}
// if cache is disabled
if ( !MAGPIE_CACHE_ON ) {
// fetch file, and parse it
$resp = _fetch_remote_file( $url );
if ( is_success( $resp->status ) ) {
return _response_to_rss( $resp );
}
else {
error("Failed to fetch $url and cache is off");
return false;
}
}
// else cache is ON
else {
// Flow
// 1. check cache
// 2. if there is a hit, make sure its fresh
// 3. if cached obj fails freshness check, fetch remote
// 4. if remote fails, return stale object, or error
$cache = new RSSCache( MAGPIE_CACHE_DIR, MAGPIE_CACHE_AGE );
if (MAGPIE_DEBUG and $cache->ERROR) {
debug($cache->ERROR, E_USER_WARNING);
}
$cache_status = 0; // response of check_cache
$request_headers = array(); // HTTP headers to send with fetch
$rss = 0; // parsed RSS object
$errormsg = 0; // errors, if any
// store parsed XML by desired output encoding
// as character munging happens at parse time
$cache_key = $url . MAGPIE_OUTPUT_ENCODING;
if (!$cache->ERROR) {
// return cache HIT, MISS, or STALE
$cache_status = $cache->check_cache( $cache_key);
}
// if object cached, and cache is fresh, return cached obj
if ( $cache_status == 'HIT' ) {
$rss = $cache->get( $cache_key );
if ( isset($rss) and $rss ) {
// should be cache age
$rss->from_cache = 1;
if ( MAGPIE_DEBUG > 1) {
debug("MagpieRSS: Cache HIT", E_USER_NOTICE);
}
return $rss;
}
}
// else attempt a conditional get
// setup headers
if ( $cache_status == 'STALE' ) {
$rss = $cache->get( $cache_key );
if ( $rss and $rss->etag and $rss->last_modified ) {
$request_headers['If-None-Match'] = $rss->etag;
$request_headers['If-Last-Modified'] = $rss->last_modified;
}
}
$resp = _fetch_remote_file( $url, $request_headers );
if (isset($resp) and $resp) {
if ($resp->status == '304' ) {
// we have the most current copy
if ( MAGPIE_DEBUG > 1) {
debug("Got 304 for $url");
}
// reset cache on 304 (at minutillo insistent prodding)
$cache->set($cache_key, $rss);
return $rss;
}
elseif ( is_success( $resp->status ) ) {
$rss = _response_to_rss( $resp );
if ( $rss ) {
if (MAGPIE_DEBUG > 1) {
debug("Fetch successful");
}
// add object to cache
$cache->set( $cache_key, $rss );
return $rss;
}
}
else {
$errormsg = "Failed to fetch $url ";
if ( $resp->status == '-100' ) {
$errormsg .= "(Request timed out after " . MAGPIE_FETCH_TIME_OUT . " seconds)";
}
elseif ( $resp->error ) {
# compensate for Snoopy's annoying habbit to tacking
# on '\n'
$http_error = substr($resp->error, 0, -2);
$errormsg .= "(HTTP Error: $http_error)";
}
else {
$errormsg .= "(HTTP Response: " . $resp->response_code .')';
}
}
}
else {
$errormsg = "Unable to retrieve RSS file for unknown reasons.";
}
// else fetch failed
// attempt to return cached object
if ($rss) {
if ( MAGPIE_DEBUG ) {
debug("Returning STALE object for $url");
}
return $rss;
}
// else we totally failed
error( $errormsg );
return false;
} // end if ( !MAGPIE_CACHE_ON ) {
} // end fetch_rss()
/*=======================================================================*\
Function: error
Purpose: set MAGPIE_ERROR, and trigger error
\*=======================================================================*/
function error ($errormsg, $lvl=E_USER_WARNING) {
global $MAGPIE_ERROR;
// append PHP's error message if track_errors enabled
if ( isset($php_errormsg) ) {
$errormsg .= " ($php_errormsg)";
}
if ( $errormsg ) {
$errormsg = "MagpieRSS: $errormsg";
$MAGPIE_ERROR = $errormsg;
trigger_error( $errormsg, $lvl);
}
}
function debug ($debugmsg, $lvl=E_USER_NOTICE) {
trigger_error("MagpieRSS [debug] $debugmsg", $lvl);
}
/*=======================================================================*\
Function: magpie_error
Purpose: accessor for the magpie error variable
\*=======================================================================*/
function magpie_error ($errormsg="") {
global $MAGPIE_ERROR;
if ( isset($errormsg) and $errormsg ) {
$MAGPIE_ERROR = $errormsg;
}
return $MAGPIE_ERROR;
}
/*=======================================================================*\
Function: _fetch_remote_file
Purpose: retrieve an arbitrary remote file
Input: url of the remote file
headers to send along with the request (optional)
Output: an HTTP response object (see Snoopy.class.inc)
\*=======================================================================*/
function _fetch_remote_file ($url, $headers = "" ) {
// Snoopy is an HTTP client in PHP
$client = new Snoopy();
$client->agent = MAGPIE_USER_AGENT;
$client->read_timeout = MAGPIE_FETCH_TIME_OUT;
$client->use_gzip = MAGPIE_USE_GZIP;
if (is_array($headers) ) {
$client->rawheaders = $headers;
}
@$client->fetch($url);
return $client;
}
/*=======================================================================*\
Function: _response_to_rss
Purpose: parse an HTTP response object into an RSS object
Input: an HTTP response object (see Snoopy)
Output: parsed RSS object (see rss_parse)
\*=======================================================================*/
function _response_to_rss ($resp) {
$rss = new MagpieRSS( $resp->results, MAGPIE_OUTPUT_ENCODING, MAGPIE_INPUT_ENCODING, MAGPIE_DETECT_ENCODING );
// if RSS parsed successfully
if ( $rss and !$rss->ERROR) {
// find Etag, and Last-Modified
foreach($resp->headers as $h) {
// 2003-03-02 - Nicola Asuni (www.tecnick.com) - fixed bug "Undefined offset: 1"
if (strpos($h, ": ")) {
list($field, $val) = explode(": ", $h, 2);
}
else {
$field = $h;
$val = "";
}
if ( $field == 'ETag' ) {
$rss->etag = $val;
}
if ( $field == 'Last-Modified' ) {
$rss->last_modified = $val;
}
}
return $rss;
} // else construct error message
else {
$errormsg = "Failed to parse RSS file.";
if ($rss) {
$errormsg .= " (" . $rss->ERROR . ")";
}
error($errormsg);
return false;
} // end if ($rss and !$rss->error)
}
/*=======================================================================*\
Function: init
Purpose: setup constants with default values
check for user overrides
\*=======================================================================*/
function init () {
if ( defined('MAGPIE_INITALIZED') ) {
return;
}
else {
define('MAGPIE_INITALIZED', true);
}
if ( !defined('MAGPIE_CACHE_ON') ) {
define('MAGPIE_CACHE_ON', true);
}
if ( !defined('MAGPIE_CACHE_DIR') ) {
define('MAGPIE_CACHE_DIR', './cache');
}
if ( !defined('MAGPIE_CACHE_AGE') ) {
define('MAGPIE_CACHE_AGE', 60*60); // one hour
}
if ( !defined('MAGPIE_CACHE_FRESH_ONLY') ) {
define('MAGPIE_CACHE_FRESH_ONLY', false);
}
if ( !defined('MAGPIE_OUTPUT_ENCODING') ) {
define('MAGPIE_OUTPUT_ENCODING', 'UTF-8');
}
if ( !defined('MAGPIE_INPUT_ENCODING') ) {
define('MAGPIE_INPUT_ENCODING', null);
}
if ( !defined('MAGPIE_DETECT_ENCODING') ) {
define('MAGPIE_DETECT_ENCODING', true);
}
if ( !defined('MAGPIE_DEBUG') ) {
define('MAGPIE_DEBUG', 0);
}
if ( !defined('MAGPIE_USER_AGENT') ) {
$ua = 'MagpieRSS/'. MAGPIE_VERSION . ' (+http://magpierss.sf.net';
if ( MAGPIE_CACHE_ON ) {
$ua = $ua . ')';
}
else {
$ua = $ua . '; No cache)';
}
define('MAGPIE_USER_AGENT', $ua);
}
if ( !defined('MAGPIE_FETCH_TIME_OUT') ) {
define('MAGPIE_FETCH_TIME_OUT', 5); // 5 second timeout
}
// use gzip encoding to fetch rss files if supported?
if ( !defined('MAGPIE_USE_GZIP') ) {
define('MAGPIE_USE_GZIP', true);
}
}
// NOTE: the following code should really be in Snoopy, or at least
// somewhere other then rss_fetch!
/*=======================================================================*\
HTTP STATUS CODE PREDICATES
These functions attempt to classify an HTTP status code
based on RFC 2616 and RFC 2518.
All of them take an HTTP status code as input, and return true or false
All this code is adapted from LWP's HTTP::Status.
\*=======================================================================*/
/*=======================================================================*\
Function: is_info
Purpose: return true if Informational status code
\*=======================================================================*/
function is_info ($sc) {
return $sc >= 100 && $sc < 200;
}
/*=======================================================================*\
Function: is_success
Purpose: return true if Successful status code
\*=======================================================================*/
function is_success ($sc) {
return $sc >= 200 && $sc < 300;
}
/*=======================================================================*\
Function: is_redirect
Purpose: return true if Redirection status code
\*=======================================================================*/
function is_redirect ($sc) {
return $sc >= 300 && $sc < 400;
}
/*=======================================================================*\
Function: is_error
Purpose: return true if Error status code
\*=======================================================================*/
function is_error ($sc) {
return $sc >= 400 && $sc < 600;
}
/*=======================================================================*\
Function: is_client_error
Purpose: return true if Error status code, and its a client error
\*=======================================================================*/
function is_client_error ($sc) {
return $sc >= 400 && $sc < 500;
}
/*=======================================================================*\
Function: is_client_error
Purpose: return true if Error status code, and its a server error
\*=======================================================================*/
function is_server_error ($sc) {
return $sc >= 500 && $sc < 600;
}
?>

View File

@@ -0,0 +1,605 @@
<?php
/**
* Project: MagpieRSS: a simple RSS integration tool
* File: rss_parse.inc - parse an RSS or Atom feed
* return as a simple object.
*
* Handles RSS 0.9x, RSS 2.0, RSS 1.0, and Atom 0.3
*
* The lastest version of MagpieRSS can be obtained from:
* http://magpierss.sourceforge.net
*
* For questions, help, comments, discussion, etc., please join the
* Magpie mailing list:
* magpierss-general@lists.sourceforge.net
*
* @author Kellan Elliott-McCrea <kellan@protest.net>
* @version 0.7a
* @license GPL
*
*/
define('RSS', 'RSS');
define('ATOM', 'Atom');
require_once (MAGPIE_DIR . 'rss_utils.inc');
/**
* Hybrid parser, and object, takes RSS as a string and returns a simple object.
*
* see: rss_fetch.inc for a simpler interface with integrated caching support
*
*/
class MagpieRSS {
var $parser;
var $current_item = array(); // item currently being parsed
var $items = array(); // collection of parsed items
var $channel = array(); // hash of channel fields
var $textinput = array();
var $image = array();
var $feed_type;
var $feed_version;
var $encoding = ''; // output encoding of parsed rss
var $_source_encoding = ''; // only set if we have to parse xml prolog
var $ERROR = "";
var $WARNING = "";
// define some constants
var $_CONTENT_CONSTRUCTS = array('content', 'summary', 'info', 'title', 'tagline', 'copyright');
var $_KNOWN_ENCODINGS = array('UTF-8', 'US-ASCII', 'UTF-8');
// parser variables, useless if you're not a parser, treat as private
var $stack = array(); // parser stack
var $inchannel = false;
var $initem = false;
var $incontent = false; // if in Atom <content mode="xml"> field
var $intextinput = false;
var $inimage = false;
var $current_namespace = false;
/**
* Set up XML parser, parse source, and return populated RSS object..
*
* @param string $source string containing the RSS to be parsed
*
* NOTE: Probably a good idea to leave the encoding options alone unless
* you know what you're doing as PHP's character set support is
* a little weird.
*
* NOTE: A lot of this is unnecessary but harmless with PHP5
*
*
* @param string $output_encoding output the parsed RSS in this character
* set defaults to ISO-8859-1 as this is PHP's
* default.
*
* NOTE: might be changed to UTF-8 in future
* versions.
*
* @param string $input_encoding the character set of the incoming RSS source.
* Leave blank and Magpie will try to figure it
* out.
*
*
* @param bool $detect_encoding if false Magpie won't attempt to detect
* source encoding. (caveat emptor)
*
*/
function MagpieRSS ($source, $output_encoding='UTF-8',
$input_encoding=null, $detect_encoding=true)
{
# if PHP xml isn't compiled in, die
#
if (!function_exists('xml_parser_create')) {
$this->error( "Failed to load PHP's XML Extension. " .
"http://www.php.net/manual/en/ref.xml.php",
E_USER_ERROR );
}
list($parser, $source) = $this->create_parser($source,
$output_encoding, $input_encoding, $detect_encoding);
if (!is_resource($parser)) {
$this->error( "Failed to create an instance of PHP's XML parser. " .
"http://www.php.net/manual/en/ref.xml.php",
E_USER_ERROR );
}
$this->parser = $parser;
# pass in parser, and a reference to this object
# setup handlers
#
xml_set_object( $this->parser, $this );
xml_set_element_handler($this->parser,
'feed_start_element', 'feed_end_element' );
xml_set_character_data_handler( $this->parser, 'feed_cdata' );
$status = xml_parse( $this->parser, $source );
if (! $status ) {
$errorcode = xml_get_error_code( $this->parser );
if ( $errorcode != XML_ERROR_NONE ) {
$xml_error = xml_error_string( $errorcode );
$error_line = xml_get_current_line_number($this->parser);
$error_col = xml_get_current_column_number($this->parser);
$errormsg = "$xml_error at line $error_line, column $error_col";
$this->error( $errormsg );
}
}
xml_parser_free( $this->parser );
$this->normalize();
}
function feed_start_element($p, $element, &$attrs) {
$el = $element = strtolower($element);
$attrs = array_change_key_case($attrs, CASE_LOWER);
// check for a namespace, and split if found
$ns = false;
if ( strpos( $element, ':' ) ) {
list($ns, $el) = split( ':', $element, 2);
}
if ( $ns and $ns != 'rdf' ) {
$this->current_namespace = $ns;
}
# if feed type isn't set, then this is first element of feed
# identify feed from root element
#
if (!isset($this->feed_type) ) {
if ( $el == 'rdf' ) {
$this->feed_type = RSS;
$this->feed_version = '1.0';
}
elseif ( $el == 'rss' ) {
$this->feed_type = RSS;
$this->feed_version = $attrs['version'];
}
elseif ( $el == 'feed' ) {
$this->feed_type = ATOM;
$this->feed_version = $attrs['version'];
$this->inchannel = true;
}
return;
}
if ( $el == 'channel' )
{
$this->inchannel = true;
}
elseif ($el == 'item' or $el == 'entry' )
{
$this->initem = true;
if ( isset($attrs['rdf:about']) ) {
$this->current_item['about'] = $attrs['rdf:about'];
}
}
// if we're in the default namespace of an RSS feed,
// record textinput or image fields
elseif (
$this->feed_type == RSS and
$this->current_namespace == '' and
$el == 'textinput' )
{
$this->intextinput = true;
}
elseif (
$this->feed_type == RSS and
$this->current_namespace == '' and
$el == 'image' )
{
$this->inimage = true;
}
# handle atom content constructs
elseif ( $this->feed_type == ATOM and in_array($el, $this->_CONTENT_CONSTRUCTS) )
{
// avoid clashing w/ RSS mod_content
if ($el == 'content' ) {
$el = 'atom_content';
}
$this->incontent = $el;
}
// if inside an Atom content construct (e.g. content or summary) field treat tags as text
elseif ($this->feed_type == ATOM and $this->incontent )
{
// if tags are inlined, then flatten
$attrs_str = join(' ',
array_map('map_attrs',
array_keys($attrs),
array_values($attrs) ) );
$this->append_content( "<$element $attrs_str>" );
array_unshift( $this->stack, $el );
}
// Atom support many links per containging element.
// Magpie treats link elements of type rel='alternate'
// as being equivalent to RSS's simple link element.
//
elseif ($this->feed_type == ATOM and $el == 'link' )
{
if ( isset($attrs['rel']) and $attrs['rel'] == 'alternate' )
{
$link_el = 'link';
}
else {
$link_el = 'link_' . $attrs['rel'];
}
$this->append($link_el, $attrs['href']);
}
// set stack[0] to current element
else {
array_unshift($this->stack, $el);
}
}
function feed_cdata ($p, $text) {
if ($this->feed_type == ATOM and $this->incontent)
{
$this->append_content( $text );
}
else {
$current_el = join('_', array_reverse($this->stack));
$this->append($current_el, $text);
}
}
function feed_end_element ($p, $el) {
$el = strtolower($el);
if ( $el == 'item' or $el == 'entry' )
{
$this->items[] = $this->current_item;
$this->current_item = array();
$this->initem = false;
}
elseif ($this->feed_type == RSS and $this->current_namespace == '' and $el == 'textinput' )
{
$this->intextinput = false;
}
elseif ($this->feed_type == RSS and $this->current_namespace == '' and $el == 'image' )
{
$this->inimage = false;
}
elseif ($this->feed_type == ATOM and in_array($el, $this->_CONTENT_CONSTRUCTS) )
{
$this->incontent = false;
}
elseif ($el == 'channel' or $el == 'feed' )
{
$this->inchannel = false;
}
elseif ($this->feed_type == ATOM and $this->incontent ) {
// balance tags properly
// note: i don't think this is actually neccessary
if ( $this->stack[0] == $el )
{
$this->append_content("</$el>");
}
else {
$this->append_content("<$el />");
}
array_shift( $this->stack );
}
else {
array_shift( $this->stack );
}
$this->current_namespace = false;
}
function concat (&$str1, $str2="") {
if (!isset($str1) ) {
$str1="";
}
$str1 .= $str2;
}
function append_content($text) {
if ( $this->initem ) {
$this->concat( $this->current_item[ $this->incontent ], $text );
}
elseif ( $this->inchannel ) {
$this->concat( $this->channel[ $this->incontent ], $text );
}
}
// smart append - field and namespace aware
function append($el, $text) {
if (!$el) {
return;
}
if ( $this->current_namespace )
{
if ( $this->initem ) {
$this->concat(
$this->current_item[ $this->current_namespace ][ $el ], $text);
}
elseif ($this->inchannel) {
$this->concat(
$this->channel[ $this->current_namespace][ $el ], $text );
}
elseif ($this->intextinput) {
$this->concat(
$this->textinput[ $this->current_namespace][ $el ], $text );
}
elseif ($this->inimage) {
$this->concat(
$this->image[ $this->current_namespace ][ $el ], $text );
}
}
else {
if ( $this->initem ) {
$this->concat(
$this->current_item[ $el ], $text);
}
elseif ($this->intextinput) {
$this->concat(
$this->textinput[ $el ], $text );
}
elseif ($this->inimage) {
$this->concat(
$this->image[ $el ], $text );
}
elseif ($this->inchannel) {
$this->concat(
$this->channel[ $el ], $text );
}
}
}
function normalize () {
// if atom populate rss fields
if ( $this->is_atom() ) {
$this->channel['description'] = $this->channel['tagline'];
for ( $i = 0; $i < count($this->items); $i++) {
$item = $this->items[$i];
if ( isset($item['summary']) )
$item['description'] = $item['summary'];
if ( isset($item['atom_content']))
$item['content']['encoded'] = $item['atom_content'];
$atom_date = (isset($item['issued']) ) ? $item['issued'] : $item['modified'];
if ( $atom_date ) {
$epoch = @parse_w3cdtf($atom_date);
if ($epoch and $epoch > 0) {
$item['date_timestamp'] = $epoch;
}
}
$this->items[$i] = $item;
}
}
elseif ( $this->is_rss() ) {
$this->channel['tagline'] = $this->channel['description'];
for ( $i = 0; $i < count($this->items); $i++) {
$item = $this->items[$i];
if ( isset($item['description']))
$item['summary'] = $item['description'];
if ( isset($item['content']['encoded'] ) )
$item['atom_content'] = $item['content']['encoded'];
if ( $this->is_rss() == '1.0' and isset($item['dc']['date']) ) {
$epoch = @parse_w3cdtf($item['dc']['date']);
if ($epoch and $epoch > 0) {
$item['date_timestamp'] = $epoch;
}
}
elseif ( isset($item['pubdate']) ) {
$epoch = @strtotime($item['pubdate']);
if ($epoch > 0) {
$item['date_timestamp'] = $epoch;
}
}
$this->items[$i] = $item;
}
}
}
function is_rss () {
if ( $this->feed_type == RSS ) {
return $this->feed_version;
}
else {
return false;
}
}
function is_atom() {
if ( $this->feed_type == ATOM ) {
return $this->feed_version;
}
else {
return false;
}
}
/**
* return XML parser, and possibly re-encoded source
*
*/
function create_parser($source, $out_enc, $in_enc, $detect) {
if ( substr(phpversion(),0,1) == 5) {
$parser = $this->php5_create_parser($in_enc, $detect);
}
else {
list($parser, $source) = $this->php4_create_parser($source, $in_enc, $detect);
}
if ($out_enc) {
$this->encoding = $out_enc;
xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $out_enc);
}
return array($parser, $source);
}
/**
* Instantiate an XML parser under PHP5
*
* PHP5 will do a fine job of detecting input encoding
* if passed an empty string as the encoding.
*
* All hail libxml2!
*
*/
function php5_create_parser($in_enc, $detect) {
// by default php5 does a fine job of detecting input encodings
if(!$detect && $in_enc) {
return xml_parser_create($in_enc);
}
else {
return xml_parser_create('');
}
}
/**
* Instaniate an XML parser under PHP4
*
* Unfortunately PHP4's support for character encodings
* and especially XML and character encodings sucks. As
* long as the documents you parse only contain characters
* from the ISO-8859-1 character set (a superset of ASCII,
* and a subset of UTF-8) you're fine. However once you
* step out of that comfy little world things get mad, bad,
* and dangerous to know.
*
* The following code is based on SJM's work with FoF
* @see http://minutillo.com/steve/weblog/2004/6/17/php-xml-and-character-encodings-a-tale-of-sadness-rage-and-data-loss
*
*/
function php4_create_parser($source, $in_enc, $detect) {
if ( !$detect ) {
return array(xml_parser_create($in_enc), $source);
}
if (!$in_enc) {
if (preg_match('/<?xml.*encoding=[\'"](.*?)[\'"].*?>/m', $source, $m)) {
$in_enc = strtoupper($m[1]);
$this->source_encoding = $in_enc;
}
else {
$in_enc = 'UTF-8';
}
}
if ($this->known_encoding($in_enc)) {
return array(xml_parser_create($in_enc), $source);
}
// the dectected encoding is not one of the simple encodings PHP knows
// attempt to use the iconv extension to
// cast the XML to a known encoding
// @see http://php.net/iconv
if (function_exists('iconv')) {
$encoded_source = iconv($in_enc,'UTF-8', $source);
if ($encoded_source) {
return array(xml_parser_create('UTF-8'), $encoded_source);
}
}
// iconv didn't work, try mb_convert_encoding
// @see http://php.net/mbstring
if(function_exists('mb_convert_encoding')) {
$encoded_source = mb_convert_encoding($source, 'UTF-8', $in_enc );
if ($encoded_source) {
return array(xml_parser_create('UTF-8'), $encoded_source);
}
}
// else
$this->error("Feed is in an unsupported character encoding. ($in_enc) " .
"You may see strange artifacts, and mangled characters.",
E_USER_NOTICE);
return array(xml_parser_create(), $source);
}
function known_encoding($enc) {
$enc = strtoupper($enc);
if ( in_array($enc, $this->_KNOWN_ENCODINGS) ) {
return $enc;
}
else {
return false;
}
}
function error ($errormsg, $lvl=E_USER_WARNING) {
// append PHP's error message if track_errors enabled
if ( isset($php_errormsg) ) {
$errormsg .= " ($php_errormsg)";
}
if ( MAGPIE_DEBUG ) {
trigger_error( $errormsg, $lvl);
}
else {
error_log( $errormsg, 0);
}
$notices = E_USER_NOTICE|E_NOTICE;
if ( $lvl&$notices ) {
$this->WARNING = $errormsg;
} else {
$this->ERROR = $errormsg;
}
}
} // end class RSS
function map_attrs($k, $v) {
return "$k=\"$v\"";
}
// patch to support medieval versions of PHP4.1.x,
// courtesy, Ryan Currie, ryan@digibliss.com
if (!function_exists('array_change_key_case')) {
define("CASE_UPPER",1);
define("CASE_LOWER",0);
function array_change_key_case($array,$case=CASE_LOWER) {
if ($case=CASE_LOWER) $cmd=strtolower;
elseif ($case=CASE_UPPER) $cmd=strtoupper;
foreach($array as $key=>$value) {
$output[$cmd($key)]=$value;
}
return $output;
}
}
?>

View File

@@ -0,0 +1,67 @@
<?php
/*
* Project: MagpieRSS: a simple RSS integration tool
* File: rss_utils.inc, utility methods for working with RSS
* Author: Kellan Elliott-McCrea <kellan@protest.net>
* Version: 0.51
* License: GPL
*
* The lastest version of MagpieRSS can be obtained from:
* http://magpierss.sourceforge.net
*
* For questions, help, comments, discussion, etc., please join the
* Magpie mailing list:
* magpierss-general@lists.sourceforge.net
*/
/*======================================================================*\
Function: parse_w3cdtf
Purpose: parse a W3CDTF date into unix epoch
NOTE: http://www.w3.org/TR/NOTE-datetime
\*======================================================================*/
function parse_w3cdtf ( $date_str ) {
# regex to match wc3dtf
$pat = "/(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(:(\d{2}))?(?:([-+])(\d{2}):?(\d{2})|(Z))?/";
if ( preg_match( $pat, $date_str, $match ) ) {
list( $year, $month, $day, $hours, $minutes, $seconds) =
array( $match[1], $match[2], $match[3], $match[4], $match[5], $match[6]);
# calc epoch for current date assuming GMT
$epoch = gmmktime( $hours, $minutes, $seconds, $month, $day, $year);
$offset = 0;
if ( $match[10] == 'Z' ) {
# zulu time, aka GMT
}
else {
list( $tz_mod, $tz_hour, $tz_min ) =
array( $match[8], $match[9], $match[10]);
# zero out the variables
if ( ! $tz_hour ) { $tz_hour = 0; }
if ( ! $tz_min ) { $tz_min = 0; }
$offset_secs = (($tz_hour*60)+$tz_min)*60;
# is timezone ahead of GMT? then subtract offset
#
if ( $tz_mod == '+' ) {
$offset_secs = $offset_secs * -1;
}
$offset = $offset_secs;
}
$epoch = $epoch + $offset;
return $epoch;
}
else {
return -1;
}
}
?>

View File

@@ -0,0 +1,80 @@
<?php
ini_set('display_errors', 1);
ini_set('error_reporting', E_ALL);
define('MAGPIE_OUTPUT_ENCODING', 'UTF-8');
define('MAGPIE_DIR', '..' . DIRECTORY_SEPARATOR);
define('MAGPIE_DEBUG', 1);
// flush cache quickly for debugging purposes, don't do this on a live site
define('MAGPIE_CACHE_AGE', 10);
require_once(MAGPIE_DIR.'rss_fetch.inc');
if ( isset($_GET['url']) ) {
$url = $_GET['url'];
}
else {
$url = 'http://magpierss.sf.net/test.rss';
}
test_library_support();
$rss = fetch_rss( $url );
if ($rss) {
echo "<h3>Example Output</h3>";
echo "Channel: " . $rss->channel['title'] . "<p>";
echo "<ul>";
foreach ($rss->items as $item) {
$href = $item['link'];
$title = $item['title'];
echo "<li><a href=$href>$title</a></li>";
}
echo "</ul>";
}
else {
echo "Error: " . magpie_error();
}
?>
<form>
RSS URL: <input type="text" size="30" name="url" value="<?php echo $url ?>"><br />
<input type="submit" value="Parse RSS">
</form>
<h3>Parsed Results (var_dump'ed)</h3>
<pre>
<?php var_dump($rss); ?>
</pre>
<?php
function test_library_support() {
if (!function_exists('xml_parser_create')) {
echo "<b>Error:</b> PHP compiled without XML support (--with-xml), Mapgie won't work without PHP support for XML.<br />\n";
exit;
}
else {
echo "<b>OK:</b> Found an XML parser. <br />\n";
}
if ( ! function_exists('gzinflate') ) {
echo "<b>Warning:</b> PHP compiled without Zlib support (--with-zlib). No support for GZIP encoding.<br />\n";
}
else {
echo "<b>OK:</b> Support for GZIP encoding.<br />\n";
}
if ( ! (function_exists('iconv') and function_exists('mb_convert_encoding') ) ) {
echo "<b>Warning:</b> No support for iconv (--with-iconv) or multi-byte strings (--enable-mbstring)." .
"No support character set munging.<br />\n";
}
else {
echo "<b>OK:</b> Support for character munging.<br />\n";
}
}
?>

View File

@@ -0,0 +1,29 @@
<?php
define('MAGPIE_DIR', '..'.DIRECTORY_SEPARATOR);
require_once(MAGPIE_DIR.'rss_fetch.inc');
$url = $_GET['url'];
if ( $url ) {
$rss = fetch_rss( $url );
echo "Channel: " . $rss->channel['title'] . "<p>";
echo "<ul>";
foreach ($rss->items as $item) {
$href = $item['link'];
$title = $item['title'];
echo "<li><a href=$href>$title</a></li>";
}
echo "</ul>";
}
?>
<form>
RSS URL: <input type="text" size="30" name="url" value="<?php echo $url ?>"><br />
<input type="submit" value="Parse RSS">
</form>
<p>
<h2>Security Note:</h2>
This is a simple <b>example</b> script. If this was a <b>real</b> script we probably wouldn't allow strangers to submit random URLs, and we certainly wouldn't simply echo anything passed in the URL. Additionally its a bad idea to leave this example script lying around.
</p>

View File

@@ -0,0 +1,66 @@
<?php
define('MAGPIE_DIR', '..'.DIRECTORY_SEPARATOR);
require_once(MAGPIE_DIR.'rss_fetch.inc');
$url = $_GET['rss_url'];
?>
<html
<body LINK="#999999" VLINK="#000000">
<form>
<input type="text" name="rss_url" size="40" value="<?php echo $url ?>"><input type="Submit">
</form>
<?php
if ( $url ) {
echo "displaying: $url<p>";
$rss = fetch_rss( $url );
echo slashbox ($rss);
}
echo "<pre>";
print_r($rss);
echo "</pre>";
?>
</body>
</html>
<?php
# just some quick and ugly php to generate html
#
#
function slashbox ($rss) {
echo "<table cellpadding=2 cellspacing=0><tr>";
echo "<td bgcolor=#006666>";
# get the channel title and link properties off of the rss object
#
$title = $rss->channel['title'];
$link = $rss->channel['link'];
echo "<a href=$link><font color=#FFFFFF><b>$title</b></font></a>";
echo "</td></tr>";
# foreach over each item in the array.
# displaying simple links
#
# we could be doing all sorts of neat things with the dublin core
# info, or the event info, or what not, but keeping it simple for now.
#
foreach ($rss->items as $item ) {
echo "<tr><td bgcolor=#cccccc>";
echo "<a href=$item[link]>";
echo $item['title'];
echo "</a></td></tr>";
}
echo "</table>";
}
?>

View File

@@ -0,0 +1,58 @@
<?php
// Define path to Smarty files (don't forget trailing slash)
// and load library. (you'll want to change this value)
//
// NOTE: you can also simply add Smarty to your include path
define('SMARTY_DIR', '/home/kellan/projs/magpierss/scripts/Smarty/');
require_once(SMARTY_DIR.'Smarty.class.php');
// define path to Magpie files and load library
// (you'll want to change this value)
//
// NOTE: you can also simple add MagpieRSS to your include path
define('MAGPIE_DIR', '/home/kellan/projs/magpierss/');
require_once(MAGPIE_DIR.'rss_fetch.inc');
require_once(MAGPIE_DIR.'rss_utils.inc');
// optionally show lots of debugging info
# define('MAGPIE_DEBUG', 2);
// optionally flush cache quickly for debugging purposes,
// don't do this on a live site
# define('MAGPIE_CACHE_AGE', 10);
// use cache? default is yes. see rss_fetch for other Magpie options
# define('MAGPIE_CACHE_ON', 1)
// setup template object
$smarty = new Smarty;
$smarty->compile_check = true;
// url of an rss file
$url = $_GET['rss_url'];
if ( $url ) {
// assign a variable to smarty for use in the template
$smarty->assign('rss_url', $url);
// use MagpieRSS to fetch remote RSS file, and parse it
$rss = fetch_rss( $url );
// if fetch_rss returned false, we encountered an error
if ( !$rss ) {
$smarty->assign( 'error', magpie_error() );
}
$smarty->assign('rss', $rss );
$item = $rss->items[0];
$date = parse_w3cdtf( $item['dc']['date'] );
$smarty->assign( 'date', $date );
}
// parse smarty template, and display using the variables we assigned
$smarty->display('simple.smarty');
?>

View File

@@ -0,0 +1,31 @@
<?php
/*
* Smarty plugin
* -------------------------------------------------------------
* Type: modifier
* Name: rss_date_parse
* Purpose: parse rss date into unix epoch
* Input: string: rss date
* default_date: default date if $rss_date is empty
*
* NOTE!!! parse_w3cdtf provided by MagpieRSS's rss_utils.inc
* this file needs to be included somewhere in your script
* -------------------------------------------------------------
*/
function smarty_modifier_rss_date_parse ($rss_date, $default_date=null)
{
if($rss_date != '') {
return parse_w3cdtf( $rss_date );
} elseif (isset($default_date) && $default_date != '') {
return parse_w3cdtf( $default_date );
} else {
return;
}
}
?>

View File

@@ -0,0 +1,46 @@
<html>
<head>
<title>A Simple RSS Box: I'm not a designer</title>
</head>
<body>
<form>
<b>RSS File:</b>
<input type=text" name="rss_url" value="{$rss_url}" size="50">
<input type="submit">
</form>
<b>Displaying:</b> {$rss_url}
<p>
{* if $error display the error
elseif parsed RSS object display the RSS
else solicit user for a URL
*}
{if $error }
<b>Error:</b> {$error}
{elseif $rss}
<table border=1>
<tr>
<th colspan=2>
<a href="{$rss->channel.link}">{$rss->channel.title}</a>
</th>
</tr>
{foreach from=$rss->items item=item}
<tr>
<td>
<a href="{$item.link}">{$item.title}</a>
</td>
<td>
{$item.dc.date|rss_date_parse|date_format:"%A, %B %e, %Y"}
</td>
</tr>
{/foreach}
</table>
{else}
Enter the URL of an RSS file to display.
{/if}
</body>
</html>

View File

@@ -0,0 +1,523 @@
<?php
// 15/07/2006 (2.6)
// - Changed the algorithm to parse the ZIP file.. Now, the script will try to mount the compressed
// list, searching on the 'Central Dir' records. If it fails, the script will try to search by
// checking every signature. Thanks to Jayson Cruz for pointing it.
// 25/01/2006 (2.51)
// - Fixed bug when calling 'unzip' without calling 'getList' first. Thanks to Bala Murthu for pointing it.
// 01/12/2006 (2.5)
// - Added optional parameter "applyChmod" for the "unzip()" method. It auto applies the given chmod for
// extracted files.
// - Permission 777 (all read-write-exec) is default. If you want to change it, you'll need to make it
// explicit. (If you want the OS to determine, set "false" as "applyChmod" parameter)
// 28/11/2005 (2.4)
// - dUnzip2 is now compliant with old-style "Data Description", made by some compressors,
// like the classes ZipLib and ZipLib2 by 'Hasin Hayder'. Thanks to Ricardo Parreno for pointing it.
// 09/11/2005 (2.3)
// - Added optional parameter '$stopOnFile' on method 'getList()'.
// If given, file listing will stop when find given filename. (Useful to open and unzip an exact file)
// 06/11/2005 (2.21)
// - Added support to PK00 file format (Packed to Removable Disk) (thanks to Lito [PHPfileNavigator])
// - Method 'getExtraInfo': If requested file doesn't exist, return FALSE instead of Array()
// 31/10/2005 (2.2)
// - Removed redundant 'file_name' on centralDirs declaration (thanks to Lito [PHPfileNavigator])
// - Fixed redeclaration of file_put_contents when in PHP4 (not returning true)
##############################################################
# Class dUnzip2 v2.6
#
# Author: Alexandre Tedeschi (d)
# E-Mail: alexandrebr at gmail dot com
# Londrina - PR / Brazil
#
# Objective:
# This class allows programmer to easily unzip files on the fly.
#
# Requirements:
# This class requires extension ZLib Enabled. It is default
# for most site hosts around the world, and for the PHP Win32 dist.
#
# To do:
# * Error handling
# * Write a PHP-Side gzinflate, to completely avoid any external extensions
# * Write other decompress algorithms
#
# If you modify this class, or have any ideas to improve it, please contact me!
# You are allowed to redistribute this class, if you keep my name and contact e-mail on it.
#
# PLEASE! IF YOU USE THIS CLASS IN ANY OF YOUR PROJECTS, PLEASE LET ME KNOW!
# If you have problems using it, don't think twice before contacting me!
#
##############################################################
if (!function_exists('file_put_contents')) {
// If not PHP5, creates a compatible function
function file_put_contents($file, $data) {
if ($tmp = fopen($file, "w")) {
fwrite($tmp, $data);
fclose($tmp);
return true;
}
echo "<b>file_put_contents:</b> Cannot create file $file<br>";
return false;
}
}
class dUnzip2{
function getVersion() {
return "2.6";
}
// Public
var $fileName;
var $compressedList; // You will problably use only this one!
var $centralDirList; // Central dir list... It's a kind of 'extra attributes' for a set of files
var $endOfCentral; // End of central dir, contains ZIP Comments
var $debug;
var $errors = false;
// Private
var $fh;
var $zipSignature = "\x50\x4b\x03\x04"; // local file header signature
var $dirSignature = "\x50\x4b\x01\x02"; // central dir header signature
var $dirSignatureE= "\x50\x4b\x05\x06"; // end of central dir signature
// Public
function dUnzip2($fileName) {
$this->fileName = $fileName;
$this->compressedList =
$this->centralDirList =
$this->endOfCentral = Array();
}
function getList($stopOnFile=false) {
if(sizeof($this->compressedList)){
$this->debugMsg(1, "Returning already loaded file list.");
return $this->compressedList;
}
// Open file, and set file handler
$fh = fopen($this->fileName, "r");
$this->fh = &$fh;
if(!$fh){
$this->debugMsg(2, "Failed to load file.");
return false;
}
$this->debugMsg(1, "Loading list from 'End of Central Dir' index list...");
if(!$this->_loadFileListByEOF($fh, $stopOnFile)){
$this->debugMsg(1, "Failed! Trying to load list looking for signatures...");
if(!$this->_loadFileListBySignatures($fh, $stopOnFile)){
$this->debugMsg(1, "Failed! Could not find any valid header.");
$this->debugMsg(2, "ZIP File is corrupted or empty");
return false;
}
}
if ($this->debug) {
#------- Debug compressedList
$kkk = 0;
echo "<table border='0' style='font: 11px Verdana; border: 1px solid #000'>";
foreach($this->compressedList as $fileName=>$item){
if(!$kkk && $kkk=1){
echo "<tr style='background: #ADA'>";
foreach($item as $fieldName=>$value)
echo "<td>$fieldName</td>";
echo '</tr>';
}
echo "<tr style='background: #CFC'>";
foreach($item as $fieldName=>$value){
if($fieldName == 'lastmod_datetime')
echo "<td title='$fieldName' nowrap='nowrap'>".date("d/m/Y H:i:s", $value)."</td>";
else
echo "<td title='$fieldName' nowrap='nowrap'>$value</td>";
}
echo "</tr>";
}
echo "</table>";
#------- Debug centralDirList
$kkk = 0;
if(sizeof($this->centralDirList)){
echo "<table border='0' style='font: 11px Verdana; border: 1px solid #000'>";
foreach($this->centralDirList as $fileName=>$item){
if(!$kkk && $kkk=1){
echo "<tr style='background: #AAD'>";
foreach($item as $fieldName=>$value)
echo "<td>$fieldName</td>";
echo '</tr>';
}
echo "<tr style='background: #CCF'>";
foreach($item as $fieldName=>$value){
if($fieldName == 'lastmod_datetime')
echo "<td title='$fieldName' nowrap='nowrap'>".date("d/m/Y H:i:s", $value)."</td>";
else
echo "<td title='$fieldName' nowrap='nowrap'>$value</td>";
}
echo "</tr>";
}
echo "</table>";
}
#------- Debug endOfCentral
$kkk = 0;
if(sizeof($this->endOfCentral)){
echo "<table border='0' style='font: 11px Verdana' style='border: 1px solid #000'>";
echo "<tr style='background: #DAA'><td colspan='2'>dUnzip - End of file</td></tr>";
foreach($this->endOfCentral as $field=>$value){
echo "<tr>";
echo "<td style='background: #FCC'>$field</td>";
echo "<td style='background: #FDD'>$value</td>";
echo "</tr>";
}
echo "</table>";
}
}
return $this->compressedList;
}
function getExtraInfo($compressedFileName){
return isset($this->centralDirList[$compressedFileName]) ? $this->centralDirList[$compressedFileName] : false;
}
function getZipInfo($detail=false){
return $detail?
$this->endOfCentral[$detail]:
$this->endOfCentral;
}
function unzip($compressedFileName, $targetFileName=false, $applyChmod=0777){
if(!sizeof($this->compressedList)){
$this->debugMsg(1, "Trying to unzip before loading file list... Loading it!");
$this->getList(false, $compressedFileName);
}
$fdetails = &$this->compressedList[$compressedFileName];
if (!isset($this->compressedList[$compressedFileName])) {
$this->debugMsg(2, "File '<b>$compressedFileName</b>' is not compressed in the zip.");
return false;
}
if (substr($compressedFileName, -1) == "/") {
$this->debugMsg(2, "Trying to unzip a folder name '<b>$compressedFileName</b>'.");
return false;
}
if (!$fdetails['uncompressed_size']) {
$this->debugMsg(1, "File '<b>$compressedFileName</b>' is empty.");
return $targetFileName?
file_put_contents($targetFileName, ""):
"";
}
fseek($this->fh, $fdetails['contents-startOffset']);
$ret = $this->uncompress(
fread($this->fh, $fdetails['compressed_size']),
$fdetails['compression_method'],
$fdetails['uncompressed_size'],
$targetFileName
);
if ($applyChmod && $targetFileName) @chmod($targetFileName, 0777);
if ($ret === false) $this->errors[] = $targetFileName;
return $ret;
}
function unzipAll($targetDir=false, $baseDir="", $maintainStructure=true, $applyChmod=0777){
if ($targetDir === false) $targetDir = dirname(__FILE__)."/";
$lista = $this->getList();
if (sizeof($lista)) {
foreach($lista as $fileName=>$trash){
$dirname = dirname($fileName);
$outDN = "$targetDir/$dirname";
if (substr($dirname, 0, strlen($baseDir)) != $baseDir) continue;
if (!is_dir($outDN) && $maintainStructure) {
$str = "";
$folders = explode("/", $dirname);
foreach ($folders as $folder) {
$str = $str ? "$str/$folder" : $folder;
if (!is_dir("$targetDir/$str")) {
$this->debugMsg(1, "Creating folder: $targetDir/$str");
mkdir("$targetDir/$str");
if ($applyChmod) chmod("$targetDir/$str", $applyChmod);
}
}
}
if (substr($fileName, -1, 1) == "/") continue;
$maintainStructure ?
$this->unzip($fileName, "$targetDir/$fileName", $applyChmod) :
$this->unzip($fileName, "$targetDir/".basename($fileName), $applyChmod);
}
}
}
function close() { // Free the file resource
if($this->fh)
fclose($this->fh);
}
function __destroy() {
$this->close();
}
function getErrors() {
if (is_array($this->errors)) {
return $this->errors;
}
return false;
}
// Private (you should NOT call these methods):
function uncompress($content, $mode, $uncompressedSize, $targetFileName=false){
switch($mode){
case 0:
// Not compressed
return $targetFileName?
file_put_contents($targetFileName, $content):
$content;
case 1:
$this->debugMsg(2, "Shrunk mode is not supported... yet?");
return false;
case 2:
case 3:
case 4:
case 5:
$this->debugMsg(2, "Compression factor ".($mode-1)." is not supported... yet?");
return false;
case 6:
$this->debugMsg(2, "Implode is not supported... yet?");
return false;
case 7:
$this->debugMsg(2, "Tokenizing compression algorithm is not supported... yet?");
return false;
case 8:
// Deflate
return $targetFileName?
file_put_contents($targetFileName, gzinflate($content, $uncompressedSize)):
gzinflate($content, $uncompressedSize);
case 9:
$this->debugMsg(2, "Enhanced Deflating is not supported... yet?");
return false;
case 10:
$this->debugMsg(2, "PKWARE Date Compression Library Impoloding is not supported... yet?");
return false;
case 12:
// Bzip2
return $targetFileName?
file_put_contents($targetFileName, bzdecompress($content)):
bzdecompress($content);
case 18:
$this->debugMsg(2, "IBM TERSE is not supported... yet?");
return false;
default:
$this->debugMsg(2, "Unknown uncompress method: $mode");
return false;
}
}
function debugMsg($level, $string){
if($this->debug)
if($level == 1)
echo "<b style='color: #777'>dUnzip2:</b> $string<br>";
if($level == 2)
echo "<b style='color: #F00'>dUnzip2:</b> $string<br>";
}
function _loadFileListByEOF(&$fh, $stopOnFile=false){
// Check if there's a valid Central Dir signature.
// Let's consider a file comment smaller than 1024 characters...
// Actually, it length can be 65536.. But we're not going to support it.
for($x = 0; $x < 1024; $x++){
fseek($fh, -22-$x, SEEK_END);
$signature = fread($fh, 4);
if($signature == $this->dirSignatureE){
// If found EOF Central Dir
$eodir['disk_number_this'] = unpack("v", fread($fh, 2)); // number of this disk
$eodir['disk_number'] = unpack("v", fread($fh, 2)); // number of the disk with the start of the central directory
$eodir['total_entries_this'] = unpack("v", fread($fh, 2)); // total number of entries in the central dir on this disk
$eodir['total_entries'] = unpack("v", fread($fh, 2)); // total number of entries in
$eodir['size_of_cd'] = unpack("V", fread($fh, 4)); // size of the central directory
$eodir['offset_start_cd'] = unpack("V", fread($fh, 4)); // offset of start of central directory with respect to the starting disk number
$zipFileCommentLenght = unpack("v", fread($fh, 2)); // zipfile comment length
$eodir['zipfile_comment'] = $zipFileCommentLenght[1]?fread($fh, $zipFileCommentLenght[1]):''; // zipfile comment
$this->endOfCentral = Array(
'disk_number_this'=>$eodir['disk_number_this'][1],
'disk_number'=>$eodir['disk_number'][1],
'total_entries_this'=>$eodir['total_entries_this'][1],
'total_entries'=>$eodir['total_entries'][1],
'size_of_cd'=>$eodir['size_of_cd'][1],
'offset_start_cd'=>$eodir['offset_start_cd'][1],
'zipfile_comment'=>$eodir['zipfile_comment'],
);
// Then, load file list
fseek($fh, $this->endOfCentral['offset_start_cd']);
$signature = fread($fh, 4);
while($signature == $this->dirSignature){
$dir['version_madeby'] = unpack("v", fread($fh, 2)); // version made by
$dir['version_needed'] = unpack("v", fread($fh, 2)); // version needed to extract
$dir['general_bit_flag'] = unpack("v", fread($fh, 2)); // general purpose bit flag
$dir['compression_method'] = unpack("v", fread($fh, 2)); // compression method
$dir['lastmod_time'] = unpack("v", fread($fh, 2)); // last mod file time
$dir['lastmod_date'] = unpack("v", fread($fh, 2)); // last mod file date
$dir['crc-32'] = fread($fh, 4); // crc-32
$dir['compressed_size'] = unpack("V", fread($fh, 4)); // compressed size
$dir['uncompressed_size'] = unpack("V", fread($fh, 4)); // uncompressed size
$fileNameLength = unpack("v", fread($fh, 2)); // filename length
$extraFieldLength = unpack("v", fread($fh, 2)); // extra field length
$fileCommentLength = unpack("v", fread($fh, 2)); // file comment length
$dir['disk_number_start'] = unpack("v", fread($fh, 2)); // disk number start
$dir['internal_attributes'] = unpack("v", fread($fh, 2)); // internal file attributes-byte1
$dir['external_attributes1']= unpack("v", fread($fh, 2)); // external file attributes-byte2
$dir['external_attributes2']= unpack("v", fread($fh, 2)); // external file attributes
$dir['relative_offset'] = unpack("V", fread($fh, 4)); // relative offset of local header
$dir['file_name'] = fread($fh, $fileNameLength[1]); // filename
$dir['extra_field'] = $extraFieldLength[1] ?fread($fh, $extraFieldLength[1]) :''; // extra field
$dir['file_comment'] = $fileCommentLength[1]?fread($fh, $fileCommentLength[1]):''; // file comment
// Convert the date and time, from MS-DOS format to UNIX Timestamp
$BINlastmod_date = str_pad(decbin($dir['lastmod_date'][1]), 16, '0', STR_PAD_LEFT);
$BINlastmod_time = str_pad(decbin($dir['lastmod_time'][1]), 16, '0', STR_PAD_LEFT);
$lastmod_dateY = bindec(substr($BINlastmod_date, 0, 7))+1980;
$lastmod_dateM = bindec(substr($BINlastmod_date, 7, 4));
$lastmod_dateD = bindec(substr($BINlastmod_date, 11, 5));
$lastmod_timeH = bindec(substr($BINlastmod_time, 0, 5));
$lastmod_timeM = bindec(substr($BINlastmod_time, 5, 6));
$lastmod_timeS = bindec(substr($BINlastmod_time, 11, 5));
$this->centralDirList[$dir['file_name']] = Array(
'version_madeby'=>$dir['version_madeby'][1],
'version_needed'=>$dir['version_needed'][1],
'general_bit_flag'=>str_pad(decbin($dir['general_bit_flag'][1]), 8, '0', STR_PAD_LEFT),
'compression_method'=>$dir['compression_method'][1],
'lastmod_datetime' =>mktime($lastmod_timeH, $lastmod_timeM, $lastmod_timeS, $lastmod_dateM, $lastmod_dateD, $lastmod_dateY),
'crc-32' =>str_pad(dechex(ord($dir['crc-32'][3])), 2, '0', STR_PAD_LEFT).
str_pad(dechex(ord($dir['crc-32'][2])), 2, '0', STR_PAD_LEFT).
str_pad(dechex(ord($dir['crc-32'][1])), 2, '0', STR_PAD_LEFT).
str_pad(dechex(ord($dir['crc-32'][0])), 2, '0', STR_PAD_LEFT),
'compressed_size'=>$dir['compressed_size'][1],
'uncompressed_size'=>$dir['uncompressed_size'][1],
'disk_number_start'=>$dir['disk_number_start'][1],
'internal_attributes'=>$dir['internal_attributes'][1],
'external_attributes1'=>$dir['external_attributes1'][1],
'external_attributes2'=>$dir['external_attributes2'][1],
'relative_offset'=>$dir['relative_offset'][1],
'file_name'=>$dir['file_name'],
'extra_field'=>$dir['extra_field'],
'file_comment'=>$dir['file_comment'],
);
$signature = fread($fh, 4);
}
// If loaded centralDirs, then try to identify the offsetPosition of the compressed data.
if($this->centralDirList) foreach($this->centralDirList as $filename=>$details){
$i = $this->_getFileHeaderInformation($fh, $details['relative_offset']);
$this->compressedList[$filename]['file_name'] = $filename;
$this->compressedList[$filename]['compression_method'] = $details['compression_method'];
$this->compressedList[$filename]['version_needed'] = $details['version_needed'];
$this->compressedList[$filename]['lastmod_datetime'] = $details['lastmod_datetime'];
$this->compressedList[$filename]['crc-32'] = $details['crc-32'];
$this->compressedList[$filename]['compressed_size'] = $details['compressed_size'];
$this->compressedList[$filename]['uncompressed_size'] = $details['uncompressed_size'];
$this->compressedList[$filename]['lastmod_datetime'] = $details['lastmod_datetime'];
$this->compressedList[$filename]['extra_field'] = $i['extra_field'];
$this->compressedList[$filename]['contents-startOffset']=$i['contents-startOffset'];
if(strtolower($stopOnFile) == strtolower($filename))
break;
}
return true;
}
}
return false;
}
function _loadFileListBySignatures(&$fh, $stopOnFile=false){
fseek($fh, 0);
$return = false;
for(;;){
$details = $this->_getFileHeaderInformation($fh);
if(!$details){
$this->debugMsg(1, "Invalid signature. Trying to verify if is old style Data Descriptor...");
fseek($fh, 12 - 4, SEEK_CUR); // 12: Data descriptor - 4: Signature (that will be read again)
$details = $this->_getFileHeaderInformation($fh);
}
if(!$details){
$this->debugMsg(1, "Still invalid signature. Probably reached the end of the file.");
break;
}
$filename = $details['file_name'];
$this->compressedList[$filename] = $details;
$return = true;
if(strtolower($stopOnFile) == strtolower($filename))
break;
}
return $return;
}
function _getFileHeaderInformation(&$fh, $startOffset=false){
if($startOffset !== false)
fseek($fh, $startOffset);
$signature = fread($fh, 4);
if($signature == $this->zipSignature){
# $this->debugMsg(1, "Zip Signature!");
// Get information about the zipped file
$file['version_needed'] = unpack("v", fread($fh, 2)); // version needed to extract
$file['general_bit_flag'] = unpack("v", fread($fh, 2)); // general purpose bit flag
$file['compression_method'] = unpack("v", fread($fh, 2)); // compression method
$file['lastmod_time'] = unpack("v", fread($fh, 2)); // last mod file time
$file['lastmod_date'] = unpack("v", fread($fh, 2)); // last mod file date
$file['crc-32'] = fread($fh, 4); // crc-32
$file['compressed_size'] = unpack("V", fread($fh, 4)); // compressed size
$file['uncompressed_size'] = unpack("V", fread($fh, 4)); // uncompressed size
$fileNameLength = unpack("v", fread($fh, 2)); // filename length
$extraFieldLength = unpack("v", fread($fh, 2)); // extra field length
$file['file_name'] = fread($fh, $fileNameLength[1]); // filename
$file['extra_field'] = $extraFieldLength[1]?fread($fh, $extraFieldLength[1]):''; // extra field
$file['contents-startOffset']= ftell($fh);
// Bypass the whole compressed contents, and look for the next file
fseek($fh, $file['compressed_size'][1], SEEK_CUR);
// Convert the date and time, from MS-DOS format to UNIX Timestamp
$BINlastmod_date = str_pad(decbin($file['lastmod_date'][1]), 16, '0', STR_PAD_LEFT);
$BINlastmod_time = str_pad(decbin($file['lastmod_time'][1]), 16, '0', STR_PAD_LEFT);
$lastmod_dateY = bindec(substr($BINlastmod_date, 0, 7))+1980;
$lastmod_dateM = bindec(substr($BINlastmod_date, 7, 4));
$lastmod_dateD = bindec(substr($BINlastmod_date, 11, 5));
$lastmod_timeH = bindec(substr($BINlastmod_time, 0, 5));
$lastmod_timeM = bindec(substr($BINlastmod_time, 5, 6));
$lastmod_timeS = bindec(substr($BINlastmod_time, 11, 5));
// Mount file table
$i = Array(
'file_name' =>$file['file_name'],
'compression_method'=>$file['compression_method'][1],
'version_needed' =>$file['version_needed'][1],
'lastmod_datetime' =>mktime($lastmod_timeH, $lastmod_timeM, $lastmod_timeS, $lastmod_dateM, $lastmod_dateD, $lastmod_dateY),
'crc-32' =>str_pad(dechex(ord($file['crc-32'][3])), 2, '0', STR_PAD_LEFT).
str_pad(dechex(ord($file['crc-32'][2])), 2, '0', STR_PAD_LEFT).
str_pad(dechex(ord($file['crc-32'][1])), 2, '0', STR_PAD_LEFT).
str_pad(dechex(ord($file['crc-32'][0])), 2, '0', STR_PAD_LEFT),
'compressed_size' =>$file['compressed_size'][1],
'uncompressed_size' =>$file['uncompressed_size'][1],
'extra_field' =>$file['extra_field'],
'general_bit_flag' =>str_pad(decbin($file['general_bit_flag'][1]), 8, '0', STR_PAD_LEFT),
'contents-startOffset'=>$file['contents-startOffset']
);
return $i;
}
return false;
}
}
?>

View File

@@ -0,0 +1,211 @@
<?php
/**
* Class to dynamically create a zip file (archive)
*
* @author Rochak Chauhan
*/
class createZip {
public $compressedData = array();
public $centralDirectory = array(); // central directory
public $endOfCentralDirectory = "\x50\x4b\x05\x06\x00\x00\x00\x00"; //end of Central directory record
public $oldOffset = 0;
/**
* Function to create the directory where the file(s) will be unzipped
*
* @param $directoryName string
*
*/
public function addDirectory($directoryName = 'default/') {
$directoryName = str_replace("\\", "/", $directoryName);
$feedArrayRow = "\x50\x4b\x03\x04";
$feedArrayRow .= "\x0a\x00";
$feedArrayRow .= "\x00\x00";
$feedArrayRow .= "\x00\x00";
$feedArrayRow .= "\x00\x00\x00\x00";
$feedArrayRow .= pack("V",0);
$feedArrayRow .= pack("V",0);
$feedArrayRow .= pack("V",0);
$feedArrayRow .= pack("v", strlen($directoryName) );
$feedArrayRow .= pack("v", 0 );
$feedArrayRow .= $directoryName;
$feedArrayRow .= pack("V",0);
$feedArrayRow .= pack("V",0);
$feedArrayRow .= pack("V",0);
$this -> compressedData[] = $feedArrayRow;
$newOffset = strlen(implode("", $this->compressedData));
$addCentralRecord = "\x50\x4b\x01\x02";
$addCentralRecord .="\x00\x00";
$addCentralRecord .="\x0a\x00";
$addCentralRecord .="\x00\x00";
$addCentralRecord .="\x00\x00";
$addCentralRecord .="\x00\x00\x00\x00";
$addCentralRecord .= pack("V",0);
$addCentralRecord .= pack("V",0);
$addCentralRecord .= pack("V",0);
$addCentralRecord .= pack("v", strlen($directoryName) );
$addCentralRecord .= pack("v", 0 );
$addCentralRecord .= pack("v", 0 );
$addCentralRecord .= pack("v", 0 );
$addCentralRecord .= pack("v", 0 );
$ext = "\x00\x00\x10\x00";
$ext = "\xff\xff\xff\xff";
$addCentralRecord .= pack("V", 16 );
$addCentralRecord .= pack("V", $this -> oldOffset );
$this -> oldOffset = $newOffset;
$addCentralRecord .= $directoryName;
$this -> centralDirectory[] = $addCentralRecord;
}
/**
* Function to add file(s) to the specified directory in the archive
*
* @param $directoryName string
*
*/
function addFiles($array) {
if (is_array($array)) {
foreach ($array as $file) {
$this->addFile($file);
}
} else {
$fileContents = file_get_contents($array);
$this->addFile($array);
}
}
public function addFile($data, $directoryName = 'default/') {
$directoryName = str_replace("\\", "/", $directoryName);
$feedArrayRow = "\x50\x4b\x03\x04";
$feedArrayRow .= "\x14\x00";
$feedArrayRow .= "\x00\x00";
$feedArrayRow .= "\x08\x00";
$feedArrayRow .= "\x00\x00\x00\x00";
$uncompressedLength = strlen($data);
$compression = crc32($data);
$gzCompressedData = gzcompress($data);
$gzCompressedData = substr( substr($gzCompressedData, 0, strlen($gzCompressedData) - 4), 2);
$compressedLength = strlen($gzCompressedData);
$feedArrayRow .= pack("V",$compression);
$feedArrayRow .= pack("V",$compressedLength);
$feedArrayRow .= pack("V",$uncompressedLength);
$feedArrayRow .= pack("v", strlen($directoryName) );
$feedArrayRow .= pack("v", 0 );
$feedArrayRow .= $directoryName;
$feedArrayRow .= $gzCompressedData;
$feedArrayRow .= pack("V",$compression);
$feedArrayRow .= pack("V",$compressedLength);
$feedArrayRow .= pack("V",$uncompressedLength);
$this -> compressedData[] = $feedArrayRow;
$newOffset = strlen(implode("", $this->compressedData));
$addCentralRecord = "\x50\x4b\x01\x02";
$addCentralRecord .="\x00\x00";
$addCentralRecord .="\x14\x00";
$addCentralRecord .="\x00\x00";
$addCentralRecord .="\x08\x00";
$addCentralRecord .="\x00\x00\x00\x00";
$addCentralRecord .= pack("V",$compression);
$addCentralRecord .= pack("V",$compressedLength);
$addCentralRecord .= pack("V",$uncompressedLength);
$addCentralRecord .= pack("v", strlen($directoryName) );
$addCentralRecord .= pack("v", 0 );
$addCentralRecord .= pack("v", 0 );
$addCentralRecord .= pack("v", 0 );
$addCentralRecord .= pack("v", 0 );
$addCentralRecord .= pack("V", 32 );
$addCentralRecord .= pack("V", $this -> oldOffset );
$this -> oldOffset = $newOffset;
$addCentralRecord .= $directoryName;
$this -> centralDirectory[] = $addCentralRecord;
}
/**
* Fucntion to return the zip file
*
* @return zipfile (archive)
*/
public function getZippedfile() {
$data = implode("", $this -> compressedData);
$controlDirectory = implode("", $this -> centralDirectory);
return
$data.
$controlDirectory.
$this -> endOfCentralDirectory.
pack("v", sizeof($this -> centralDirectory)).
pack("v", sizeof($this -> centralDirectory)).
pack("V", strlen($controlDirectory)).
pack("V", strlen($data)).
"\x00\x00";
}
/**
*
* Function to force the download of the archive as soon as it is created
*
* @param archiveName string - name of the created archive file
*/
public function forceDownload($archiveName) {
$headerInfo = '';
if(ini_get('zlib.output_compression')) {
ini_set('zlib.output_compression', 'Off');
}
// Security checks
if( $archiveName == "" ) {
echo "<html><title>Public Photo Directory - Download </title><body><BR><B>ERROR:</B> The download file was NOT SPECIFIED.</body></html>";
exit;
}
elseif ( ! file_exists( $archiveName ) ) {
echo "<html><title>Public Photo Directory - Download </title><body><BR><B>ERROR:</B> File not found.</body></html>";
exit;
}
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private",false);
header("Content-Type: application/zip");
header("Content-Disposition: attachment; filename=".basename($archiveName).";" );
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".filesize($archiveName));
readfile("$archiveName");
}
function saveArchive($filename) {
$fp = fopen($filename, 'wb');
fwrite($fp, $this->getZippedFile());
@fclose($fp);
}
}
?>

View File

@@ -0,0 +1,136 @@
<?php
/*
+--------------------------------------------------------------------------
| CubeCart 4
| ========================================
| CubeCart is a registered trade mark of Devellion Limited
| Copyright Devellion Limited 2006. All rights reserved.
| Devellion Limited,
| 5 Bridge Street,
| Bishops Stortford,
| HERTFORDSHIRE.
| CM23 2JU
| UNITED KINGDOM
| http://www.devellion.com
| UK Private Limited Company No. 5323904
| ========================================
| Web: http://www.cubecart.com
| Email: info (at) cubecart (dot) com
| License Type: CubeCart is NOT Open Source Software and Limitations Apply
| Licence Info: http://www.cubecart.com/site/faq/license.php
+--------------------------------------------------------------------------
| cc_admin_session.php
| ========================================
| Admin Authentication and Permissions
+--------------------------------------------------------------------------
*/
class admin_session {
var $config;
var $db;
var $glob;
var $ini;
function admin_session() {
$this->__construct();
}
function __construct() {
global $config, $db, $glob, $ini;
$this->config = $config;
$this->db = &$db;
$this->glob = $glob;
$this->ini = $ini;
}
function get_session_data() {
if (!isset($GLOBALS[CC_ADMIN_SESSION_NAME])) {
## If no session redirect to login screen
httpredir($GLOBALS['rootRel'].$this->glob['adminFile']."?_g=login&goto=".urlencode(currentPage()));
} else {
## Get session information as array
$query = sprintf("SELECT * FROM ".$this->glob['dbprefix']."CubeCart_admin_users WHERE sessId = %s", $this->db->mySQLSafe($GLOBALS[CC_ADMIN_SESSION_NAME]));
$ccAdminData = $this->db->select($query);
## Security checks
//$client_ip = (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR'];
$client_ip = get_ip_address();
if ($ccAdminData[0]['sessIp'] !== $client_ip || $ccAdminData[0]['browser'] !== $_SERVER['HTTP_USER_AGENT']) {
$this->logout();
}
## Find permissions for those who are not super users
if (!$ccAdminData[0]['isSuper']) {
$query = sprintf("SELECT %1\$sCubeCart_admin_sections.sectId, name, `read`, `write`, `edit`, `delete` FROM %1\$sCubeCart_admin_sections LEFT JOIN %1\$sCubeCart_admin_permissions ON %1\$sCubeCart_admin_sections.sectId = %1\$sCubeCart_admin_permissions.sectId WHERE adminId = %2\$s", $this->glob['dbprefix'], $this->db->mySQLSafe($ccAdminData[0]['adminId']));
$permissionArray = $this->db->select($query);
#print_r($permissionArray);
#die;
if (is_array($permissionArray)) {
for ($i=0; $i<count($permissionArray); $i++) {
foreach ($permissionArray[$i] as $key => $value) {
$masterKey = $permissionArray[$i]['name'];
$ccAdminData[0][$masterKey][$key] = $value;
}
}
}
}
return $ccAdminData[0];
}
}
function makeSessId() {
session_start();
session_regenerate_id(true);
return session_id();
}
function logout() {
## reset session data
$record['sessId'] = "''";
$record['sessIp'] = "''";
$record['browser'] = "''";
$this->db->update($this->glob['dbprefix']."CubeCart_admin_users", $record,"sessId = ".$this->db->MySQLSafe($GLOBALS[CC_ADMIN_SESSION_NAME]));
$this->set_cc_admin_cookie(CC_ADMIN_SESSION_NAME, '');
httpredir($GLOBALS['rootRel'].$this->glob['adminFile']."?_g=login");
}
function login($username, $password) {
$query = sprintf("SELECT adminId FROM %sCubeCart_admin_users WHERE username = %s AND password = %s AND failLevel < %s AND blockTime < %s", $this->glob['dbprefix'], $this->db->mySQLSafe($username), $this->db->mySQLSafe(md5($password)), $this->ini['bfattempts'], time());
$result = $this->db->select($query);
return $result;
}
function createSession($admin_id) {
$sessionId = $this->makeSessId();
$this->set_cc_admin_cookie(CC_ADMIN_SESSION_NAME, $sessionId);
## set session global var because cookie won't show until next page load
$GLOBALS[CC_ADMIN_SESSION_NAME] = $sessionId;
$record['sessId'] = "'".$sessionId."'";
## log browser & ip for security purposes no session hijacking here :)
$record['sessIp'] = $this->db->MySQLSafe(get_ip_address());
$record['browser'] = $this->db->MySQLSafe($_SERVER['HTTP_USER_AGENT']);
$this->db->update($this->glob['dbprefix']."CubeCart_admin_users", $record, "adminId = ".$admin_id);
}
function get_cookie_domain($domain) {
$cookie_domain = str_replace(array('http://', 'https://', 'www.'), '', strtolower($domain));
$cookie_domain = explode("/",$cookie_domain);
$cookie_domain = explode(":", $cookie_domain[0]);
return '.'.$cookie_domain[0];
}
function set_cc_admin_cookie($name, $value) {
$expires = 0; ## remember session until browser is closed
@setcookie($name, $value, $expires, $GLOBALS['rootRel']);
}
}
?>

View File

@@ -0,0 +1,210 @@
<?php
/*
+--------------------------------------------------------------------------
| CubeCart 4
| ========================================
| CubeCart is a registered trade mark of Devellion Limited
| Copyright Devellion Limited 2006. All rights reserved.
| Devellion Limited,
| 5 Bridge Street,
| Bishops Stortford,
| HERTFORDSHIRE.
| CM23 2JU
| UNITED KINGDOM
| http://www.devellion.com
| UK Private Limited Company No. 5323904
| ========================================
| Web: http://www.cubecart.com
| Email: info (at) cubecart (dot) com
| License Type: CubeCart is NOT Open Source Software and Limitations Apply
| Licence Info: http://www.cubecart.com/site/faq/license.php
+--------------------------------------------------------------------------
| cc_session.php
| ========================================
| Front Session Class
+--------------------------------------------------------------------------
*/
class session {
var $ccUserData;
var $ccUserBlocked = false;
var $config;
var $db;
var $glob;
var $ini;
function session() {
# $this->__construct();
#}
#function __construct() {
global $config, $db, $glob, $ini;
$this->config = $config;
$this->db = $db;
$this->glob = $glob;
$this->ini = $ini;
if (isset($_GET[CC_SESSION_NAME])) {
$this->set_cc_cookie(CC_SESSION_NAME, $_GET[CC_SESSION_NAME]);
} else {
## see if session is still in db
$query = sprintf("SELECT sessId FROM %sCubeCart_sessions WHERE sessId=%s", $this->glob['dbprefix'], $this->db->mySQLSafe($GLOBALS[CC_SESSION_NAME]));
$results = $this->db->select($query);
## !empty($results[0]['sessId']) critical incase reuslts=true if session DB table has an empty sessionId!!
if ($results && !empty($results[0]['sessId'])) {
$data["timeLast"] = $this->db->mySQLSafe(time());
$data["location"] = $this->db->mySQLSafe(currentPage());
$update = $this->db->update($this->glob['dbprefix']."CubeCart_sessions", $data, "sessId=".$this->db->mySQLSafe($results[0]['sessId']));
} else {
$this->makeSession();
}
}
## get all session data and store as class array
$query = sprintf("SELECT * FROM %1\$sCubeCart_sessions LEFT JOIN %1\$sCubeCart_customer ON %1\$sCubeCart_sessions.customer_id = %1\$sCubeCart_customer.customer_id WHERE sessId = %2\$s", $this->glob['dbprefix'], $this->db->mySQLSafe($GLOBALS[CC_SESSION_NAME]));
$result = $this->db->select($query);
// security checks
$client_ip = get_ip_address();
if (!empty($result[0]['ip']) && ($result[0]['ip'] !== $client_ip || $result[0]['browser'] !== $_SERVER['HTTP_USER_AGENT'])) {
$this->destroySession($GLOBALS[CC_SESSION_NAME]);
}
$this->ccUserData = $result[0];
if (empty($result[0]['lang'])) {
define("LANG_FOLDER", $this->config['defaultLang']);
} else {
define("LANG_FOLDER", $result[0]['lang']);
}
if (empty($result[0]['skin'])) {
define("SKIN_FOLDER", $this->config['skinDir']);
} else {
define("SKIN_FOLDER", $result[0]['skin']);
}
}
function destroySession($sessionId) {
setcookie(CC_SESSION_NAME);
$data["customer_id"] = '0';
$update = $this->db->update($this->glob['dbprefix']."CubeCart_sessions", $data,"sessId=".$this->db->mySQLSafe($GLOBALS[CC_SESSION_NAME]));
return ($update) ? true : false;
}
function makeSession() {
$sessionId = $this->makeSessId();
$this->set_cc_cookie(CC_SESSION_NAME, $sessionId);
## set session global var because cookie won't show until next page load
$GLOBALS[CC_SESSION_NAME] = $sessionId;
## insert sessionId into db
$data["sessId"] = $this->db->mySQLSafe($sessionId);
$timeNow = $this->db->mySQLSafe(time());
$data["timeStart"] = $timeNow;
$data["timeLast"] = $timeNow;
$data["customer_id"] = 0;
$data["ip"] = $this->db->mySQLSafe(get_ip_address());
$data["browser"] = $this->db->mySQLSafe($_SERVER['HTTP_USER_AGENT']);
$insert = $this->db->insert($this->glob['dbprefix']."CubeCart_sessions", $data);
$this->deleteOldSessions();
}
function deleteOldSessions() {
$expiredSessTime = time() - $this->config['sqlSessionExpiry'];
/* Stock on add to basket possibly for future
$this->reduce();
*/
## delete sessions older than time set in config file
$delete = $this->db->delete($this->glob['dbprefix']."CubeCart_sessions", "timeLast<".$expiredSessTime);
}
function authenticate($user, $pass, $remember = false) {
$user = sanitizeVar($user);
$pass = sanitizeVar($pass);
$query = "SELECT customer_id FROM ".$this->glob['dbprefix']."CubeCart_customer WHERE email=".$this->db->mySQLSafe($user)." AND password = ".$this->db->mySQLSafe(md5($pass))." AND type>0";
$customer = $this->db->select($query);
if (!$customer) {
if ($this->db->blocker($user, $this->ini['bfattempts'], $this->ini['bftime'], false, 'f')) {
$this->ccUserBlocked = true;
}
} else if ($customer[0]['customer_id']>0) {
// remember user for as long as sessions are allowed in DB
if ($remember == true) {
$this->set_cc_cookie(CC_SESSION_NAME, $GLOBALS[CC_SESSION_NAME], $this->config['sqlSessionExpiry']);
}
if ($this->db->blocker($user, $this->ini['bfattempts'], $this->ini['bftime'], true, 'f')) {
$this->ccUserBlocked = true;
} else {
$data["customer_id"] = $customer[0]['customer_id'];
$update = $this->db->update($this->glob['dbprefix']."CubeCart_sessions", $data,"sessId=".$this->db->mySQLSafe($GLOBALS[CC_SESSION_NAME]));
## "login","reg","unsubscribe","forgotPass" etc..
$redir = sanitizeVar(urldecode($_GET['redir']));
## prevent phishing attacks
if (eregi("^http://|^https://",$redir) && !eregi("^".$this->glob['storeURL']."|^".$this->config['storeURL_SSL'], $redir)) {
die("Redirect URL not allowed!");
}
if (isset($_GET['redir']) && !empty($_GET['redir']) && !eregi("logout|login|forgotPass|changePass", $redir)) {
httpredir($redir);
} else {
httpredir($GLOBALS['rootRel']."index.php");
}
}
} else if (eregi("step1", urldecode($_GET['redir']))) {
httpredir($GLOBALS['rootRel']."index.php?_g=co&_a=step1");
}
}
function makeSessId() {
session_start();
session_regenerate_id(true);
return session_id();
}
function get_cookie_domain($domain) {
$cookie_domain = str_replace(array('http://', 'https://', 'www.'), '', strtolower($domain));
$cookie_domain = explode("/", $cookie_domain);
$cookie_domain = explode(":", $cookie_domain[0]);
return '.'.$cookie_domain[0];
}
function set_cc_cookie($name, $value, $length = '') {
## only set the cookie if the visitor is not a spider or search engine system is off
if (!$this->user_is_search_engine() || $this->config['sef'] == false) {
$expires = ($length>0) ? (time()+$length) : 0;
setcookie($name, $value, $expires, $GLOBALS['rootRel']);
}
}
function user_is_search_engine() {
$user_agent = strtolower($_SERVER['HTTP_USER_AGENT']);
$spider_flag = false;
if (($user_agent != '') && (strtolower($user_agent) != 'null') && (strlen(trim($user_agent)) > 0)) {
$spiders = file(CC_ROOT_DIR.'/spiders.txt');
foreach ($spiders as $spider) {
if (($spider != '') && (strtolower($spider) != 'null') && (strlen(trim($spider)) > 0)) {
if (strpos($user_agent, trim($spider)) !== false) {
$spider_flag = TRUE;
break;
}
}
}
}
return $spider_flag;
}
}
?>

View File

@@ -0,0 +1,296 @@
<?php
/*
+--------------------------------------------------------------------------
| CubeCart 4
| ========================================
| CubeCart is a registered trade mark of Devellion Limited
| Copyright Devellion Limited 2006. All rights reserved.
| Devellion Limited,
| 5 Bridge Street,
| Bishops Stortford,
| HERTFORDSHIRE.
| CM23 2JU
| UNITED KINGDOM
| http://www.devellion.com
| UK Private Limited Company No. 5323904
| ========================================
| Web: http://www.cubecart.com
| Email: info (at) cubecart (dot) com
| License Type: CubeCart is NOT Open Source Software and Limitations Apply
| Licence Info: http://www.cubecart.com/site/faq/license.php
+--------------------------------------------------------------------------
| validateCard.php
| ========================================
| Class to Validate Credit Card
+--------------------------------------------------------------------------
*/
class validateCard {
var $data;
function check($cardNo, $issueNo='', $issueDate='', $issueFormat=4, $expireDate='', $expireFormat=4, $scReqd=false, $securityCode='') {
$cardNo = ereg_replace("[^0-9]", '', $cardNo);
## Assume success unless a rule is broken
$this->data['response'] = "SUCCESS";
## check expire date (always required)
$this->expireDate($expireDate,$expireFormat);
if ($scReqd == true) $this->securityCode($securityCode);
/************************************************
* BEGIN: Regular Expressions to validate Certain Cards
************************************************/
$mastercard = "^5[1-5][0-9]{14}$";
$visa = "^4[0-9]{12}([0-9]{3})?$";
// $americanExpress = "^3[47][0-9]{13}$"; old in 4.0.3
//$americanExpress = "((^3[47])|(^3[34])|(^3[37]))((\d{11}$)|(\d{13}$))";
$americanExpress = "^[34|37|47]([0-9]{14}|[0-9]{12})$";
$diners = "^3(0[0-5]|[68][0-9])[0-9]{11}$";
$discover = "^6011[0-9]{12}$";
$jcb = "^(3[0-9]{4}|2131|1800)[0-9]{11}$";
$australianBankCard = "^5610([0-9]{12})?$";
$enRoute = "^(2014|2149)([0-9]{11})?$";
$electron = "^(450875|48440[6-9]{1}|4844[1-4]{1}[0-9]{1}|48445[0-5]{1}|4917[3-5]{1}[0-9]{1}|491880|5[1-5]{1})([0-9]{10}|[0-9]{14})?$";//
$delta = "^(41373[3-7]{1}|4462[0-9]{2}|45397[8-9]{1}|454313|45443[2-5]{1}|454742|45672[5-9]{1}|45673[0-9]{1}|45674[0-5]{1}|4658[3-7]{1}[0-9]{1}|4659[0-5]{1}[0-9]{1}|4609[6-7]{1}[0-9]{1}|49218[1-2]{1}|498824)([0-9]{10})?$";
$solo = "^(6334[5-9]{1}[0-9]{1}|6767[0-9]{2}|3528[0-9]{2})([0-9]{10})?$";
$maestro = "^(5000[0-9]{2}|5[6-8]{1}|6[0-9]{5})([0-9]{10}|[0-9]{14})?$";
$switch = "^(49030[2-9]{1}|49033[5-9]{1}|49110[1-2]{1}|49117[4-9]{1}|49118[0-2]{1}|4936[0-9]{2}|564182|6333[1-4]{1}[0-9]{1}|6759[0-9]{2})([0-9]{10}|[0-9]{12}|[0-9]{13})?$";
/************************************************
* END: Regular Expressions to validate Certain Cards
************************************************/
if (empty($cardNo)) {
$this->error(6);
} elseif (ereg($mastercard, $cardNo)) {
$this->mod10($cardNo);
$this->data['cardType'] = "MASTERCARD";
} elseif (ereg($electron, $cardNo)) {
$this->data['cardType'] = "ELECTRON";
} elseif(ereg($visa, $cardNo)) {
## mod 10 fails on 13 length card nos :( Booooooooooooooooooooooooooooo
if (strlen($cardNo) !== 13) $this->mod10($cardNo);
$this->data['cardType'] = "VISA";
} elseif (ereg($americanExpress, $cardNo)) {
$this->mod10($cardNo);
$this->data['cardType'] = "AMERICAN EXPRESS";
} elseif (ereg($diners, $cardNo)) {
$this->mod10($cardNo);
$this->data['cardType'] = "DINERS";
} elseif (ereg($discover, $cardNo)) {
$this->mod10($cardNo);
$this->data['cardType'] = "DISCOVER";
} elseif (ereg($enRoute, $cardNo)) {
$this->data['cardType'] = "ENROUTE";
} elseif (ereg($jcb, $cardNo)) {
$this->mod10($cardNo);
$this->data['cardType'] = "JCB";
} elseif (ereg($australianBankCard, $cardNo)) {
$this->data['cardType'] = "AUSTRALIAN BANK CARD";
} elseif (ereg($delta, $cardNo)) {
$this->data['cardType'] = "DELTA";
} elseif (ereg($switch, $cardNo)) {
$this->mod10($cardNo);
$this->data['cardType'] = "SWITCH";
## switch/maestro/solo requires an issue date or number
if (!$this->issueDate($issueDate,$issueFormat) || !$this->issueNo($issueNo)) $this->error(3);
} elseif (ereg($solo, $cardNo)) {
$this->mod10($cardNo);
$this->data['cardType'] = "SOLO";
## switch/maestro/solo requires an issue date or number
if (!$this->issueDate($issueDate,$issueFormat) || !$this->issueNo($issueNo)) $this->error(3);
} elseif (ereg($maestro, $cardNo)) {
$this->mod10($cardNo);
$this->data['cardType'] = "MAESTRO";
## switch/maestro/solo requires an issue date or number
if (!$this->issueDate($issueDate,$issueFormat) || !$this->issueNo($issueNo)) $this->error(3);
} else {
$this->error(1);
}
return $this->data;
}
// LUHN formula
function mod10($cardNo) {
$numSum = 0;
for($i = 0; $i < strlen($cardNo); $i++) {
$currentNum = substr($cardNo, $i, 1);
if($i % 2 == 1) {
$currentNum *= 2;
}
if($currentNum > 9) {
$firstNum = $currentNum % 10;
$secondNum = ($currentNum - $firstNum) / 10;
$currentNum = $firstNum + $secondNum;
}
$numSum += $currentNum;
}
$passCheck = ($numSum % 10 == 0);
if($passCheck == 0){
return true;
} else {
$this->error(5);
return false;
}
}
function expireDate($expireDate,$expireFormat){
if(strlen($expireDate) !== $expireFormat){
$this->error(2);
return false;
} elseif($expireFormat == 4 && $expireDate<date("ym")) {
$this->error(2);
return false;
} elseif($expireFormat == 6 && $expireDate<date("Ym")) {
$this->error(2);
return false;
} else {
return true;
}
}
function issueDate($issueDate,$issueFormat) {
if(strlen($issueDate) !== $issueFormat){
$this->error(3);
return false;
} elseif($issueFormat == 4 && $issueDate>date("ym")) {
$this->error(3);
return false;
} elseif($issueFormat == 6 && $issueDate>date("Ym")) {
$this->error(3);
return false;
} else {
return true;
}
}
function issueNo($issueNo) {
if($issueNo>0){
return true;
} else {
return false;
}
}
function securityCode($securityCode) {
if(($securityCode>0 && $securityCode<10000) && (strlen($securityCode)==3 || strlen($securityCode)==4)) {
return true;
} else {
$this->error(4);
}
}
function error($errorCode) {
global $lang;
$this->data['response'] = "FAIL";
switch($errorCode) {
case(1):
$this->data['error'][1] = "Card not recognised!";
break;
case(2):
$this->data['error'][2] = "No expiry date was entered or it wasn't valid.";
break;
case(3):
$this->data['error'][3] = "Please enter a valid issue number or date.";
break;
case(4):
$this->data['error'][4] = "Please enter a valid security code.";
break;
case(5):
$this->data['error'][5] = "Credit card number is not valid.";
break;
case(6):
$this->data['error'][5] = "Please enter a card number.";
break;
}
}
}
?>

File diff suppressed because it is too large Load Diff