I am working with solr 6.6.0 using solr PHP client. I am adding the docs using below code and it is working properly :
foreach ($data as $key => $value) {
$docs['doc_no'.$i]['id'] = $value['id'];
$docs['doc_no'.$i]['name'] = $value['name'];
$docs['doc_no'.$i]['sub_title'] = strip_tags($value['sub_title']);
$docs['doc_no'.$i]['small_image'] = $value['small_image'];
$docs['doc_no'.$i]['project_type'] = $value['project_type'];
$docs['doc_no'.$i]['project_status'] = $value['project_status'];
$docs['doc_no'.$i]['logo'] = $value['logo'];
$docs['doc_no'.$i]['price'] = $value['price'];
$docs['doc_no'.$i]['url'] = $value['url'];
$docs['doc_no'.$i]['flat_type_desc'] = $value['flat_type_desc'];
$docs['doc_no'.$i]['project_config'] = $value['project_config'];
$docs['doc_no'.$i]['address'] = $value['address'];
$docs['doc_no'.$i]['location'] = $value['location'];
$i++;
}
//print_r($docs);exit;
$documents = array();
foreach($docs as $item => $fields) {
$part = new Apache_Solr_Document();
foreach ( $fields as $key => $value ) {
if ( is_array( $value ) ) {
foreach ( $value as $data ) {
$part->setMultiValue( $key, $data );
}
}
else{
$part->$key = $value;
}
}
$documents[] = $part;
}
try {
$solr->addDocuments( $documents );
$solr->commit();
$solr->optimize();
}
catch ( Exception $e ) {
echo $e->getMessage();
}
After executing the above code I have to manually restart the solr through cmd line and then it gets reflected, I want to ask that is every time when I add any docs in solr then I have to restart the solr manually ? Is there any other way to restart the solr automatically as soon as I have the data in docs.
Any help will be appreciated Thanks in advance.
For the submitted documents to be visible in the index, you have to issue a commit - and ask for a new reader to be opened (this is usually handled for you, so that's not usually necessary. How you do exactly that in the Drupal framework I have no idea about, but I'm guessing your Solr client has a commit method or something similar. I tried searching for the API docs, but came up empty except for the _Document class.
After a commit has been issued the index changes will be visible within a few seconds, or in the case of a soft commit (where the changes aren't persisted to disk before later) almost instantly.
You can also ask for a commitWithin interval when submitting documents, but that would also depend on how the client you're using works for how you include that parameter.
Related
I am writing a script that will use Microsoft Graph api ( using this library https://github.com/microsoftgraph/msgraph-sdk-php )
I managed to connect and search for the specific email, download the attachment but now I need to mark the email as read and set the flag but I have no idea how.
So far I have used this tutorial ( https://learn.microsoft.com/en-us/graph/tutorials/php?tabs=aad ) in order to connect and read the emails.
public static function getInbox() {
$token = GraphHelper::getUserToken();
GraphHelper::$userClient->setAccessToken($token);
// Only request specific properties
$select = '$select=from,isRead,receivedDateTime,subject,hasAttachments';
// Sort by received time, newest first
$orderBy = '$orderBy=receivedDateTime DESC';
$filter = '$filter=isRead eq false';
$requestUrl = '/me/mailFolders/inbox/messages?'.$filter.'&'.$select.'&'.$orderBy;
$messages = GraphHelper::$userClient->createCollectionRequest('GET', $requestUrl)
->setReturnType(Model\Message::class)
->setPageSize(100)
->getPage();
foreach ($messages as $message) {
if(strpos($message->getSubject(), 'XML')!==false ){
print('Message: '.$message->getSubject().PHP_EOL);echo PHP_EOL;
$expand="microsoft.graph.itemattachment/item";
$requestUrl = '/me/messages/'.$message->getId().'/attachments/?$expand= '.$expand;
$docDatas = GraphHelper::$userClient->createCollectionRequest('GET', $requestUrl)
->setReturnType(Model\Message::class)
->setPageSize(1)
->getPage();
$dat = $docDatas[0]->getProperties();
//parseXmlOrder(base64_decode($dat['contentBytes']));
$sendBody = array( 'isRead' => true );
var_dump( GraphHelper::$userClient->createRequest('PATCH', '/me/messages/'.$message->getId())
->attachBody($sendBody)
->execute() );
}
}
}
This is the code I have at the moment. Right at the end of the function I am trying to set the isRead attribute.
If someone could give me some advice where I am going wrong that would be amazing and help me stop banging my head against the wall.
Thanks,
Turns out giving readwrite persmissions does help. I only had read permissions.
I'm currently developing a CiviCRM extension, where I need to replace CiviCRM-Tokens (used in pdf and mailing generation) in html code.
I did a little bit of research in the core files and tried to recreate the behaviour in the PDFLetterCommon.php (/civicrm/CRM/Contact/Form/Task/PDFLetterCommon.php) where it replaces the tokens in the postProcess function.
Here is the original CiviCRM Code:
list($formValues, $categories, $html_message, $messageToken, $returnProperties) = self::processMessageTemplate($form);
$skipOnHold = isset($form->skipOnHold) ? $form->skipOnHold : FALSE;
$skipDeceased = isset($form->skipDeceased) ? $form->skipDeceased : TRUE;
foreach ($form->_contactIds as $item => $contactId) {
$params = array('contact_id' => $contactId);
list($contact) = CRM_Utils_Token::getTokenDetails($params,
$returnProperties,
$skipOnHold,
$skipDeceased,
NULL,
$messageToken,
'CRM_Contact_Form_Task_PDFLetterCommon'
);
...
}
And here is my version for testing:
(this code is located inside an api function in my extension)
$messageToken = CRM_Utils_Token::getTokens($params["html"]);
$returnProperties = array();
if (isset($messageToken['contact'])) {
foreach ($messageToken['contact'] as $key => $value) {
$returnProperties[$value] = 1;
}
}
$skipOnHold = FALSE;
$skipDeceased = TRUE;
$tokenParams = array("contact_id" => 67450);
list($contact) = CRM_Utils_Token::getTokenDetails($tokenParams,
$returnProperties,
$skipOnHold,
$skipDeceased,
NULL,
$messageToken,
'CRM_Contact_Form_Task_PDFLetterCommon'
);
I'm using the default values for $skipOnHold (false) and $skipDeceased (true) and also just passing one (existing) user id into the $params array ($tokenParams in my code).
Here is my problem:
My $messageToken and $returnProperties variables are being filled correctly via CiviCRM's core functions but when I pass them all into CRM_Utils_Token::getTokenDetails() the returned $contact variable holds an empty array.
I'm really out of ideas, I've been looking into CRM/Utils/Token.php where getTokenDetails() is located, but have been unsuccessful in finding the problem with my code.
Thanks in advance for any help!
If you are calling php page from web, you can give as
../../somepage.php?myid=1&trackno=2&anotherparam=3
and then you can use $_REQUEST or $_GET to retrieve the information
In command line, you can use
$options = getopt("a:b:c:"); to get the options that are passed through arguments
How to make sure, same source works either in web or in command line?
Let say your requests are like following;
WEB: http://domain.com/somepage.php?myid=1&trackno=2&anotherparam=3
CLI: php /path/to/this/php/file/somepage.php 1 2 3
You can use following php code;
<?php
if (!empty($_REQUEST)) {
$myid = $_REQUEST["myid"];
$trackno = $_REQUEST["trackno"];
$anotherparam = $_REQUEST["anotherparam"];
} else if (!empty($argv)) {
$myid = $argv[1];
$trackno = $argv[2];
$anotherparam = $argv[3];
} else {
die("Invalid request!");
}
You have already know how to handle web requests, you can refer here for more detail about $argv. Simply,
$argv[0] => scriptname(somepage.php),
$argv[1] => first param, ...,
$argv[n] => (n-1)th param
Edit:
In order to not miss order of commandline arguments, you can use naming conventions like;
php somepage.php myid_1 anotherparam_2 trackno_3
and you can use following to handle this;
foreach ($argv as $k => $v) {
if ($k == 0) continue;
$temp = explode("_", $v);
${$temp[0]} = $temp[1];
}
Simply,
myid_3 becomes $myid = 3;
variable names hidden in the values so you don't need to know about sequences
In a wordpress themed-plugin for e-commerce I have two ajax/php scripts setting cookies (both in the same directory) The ajax calls are set from the same "cart.js" The first script sets/updates an anonymous cart cookie when a cart is either created or updated. The second checks if customer/user exists, or creates one anew and --in either case -- logs them in if not already, before the cart gets passed to PayPal. As such, upon returning from paypal the customer/user (now logged in) is presented with an overview / review of the status of their orders (new and old).
On my WAMP develpment stack, this works flawlessly, while on the hosted (linux) installation
the cart_cookie script works as expected, while the checkout/customer_cookie throws...
[14-May-2013 02:08:50]
PHP Warning: session_start()
[<a href='function.session-start'>function.session-start</a>]:
Cannot send session cache limiter - headers already sent
(output started at /home2/alternam/public_html/demo/wp-content/themes/AM_Wallaby_Kids/checkout.php:2)
in /home2/alternam/public_html/demo/wp-content/plugins/cat-man/catalog-manager.php on line 23
Subsequently, the user is NOT logged in, and the cart is not converted (updated with relevant customer data). Wish I saw a way to pare this down to a minimum, but as I have no earthly idea why the two scripts behave so differently across platforms I'll apologize in advance for the lengthy post and include them both in their entirety below, and ask if anyone can see some obvious reason for the disparity? Thanks for your patience.
P.S. Both WAMP and LAMP stacks running php 5.2
cart_add.php (works both WAMP && LAMP)
<?php
ob_start();
require_once(preg_replace("/wp-content.*/","wp-load.php",__FILE__));
ob_end_clean();
$ud_cart = $product_name = $product_url = $reset = "";
$_POST = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);# Sanitize Post Input
foreach ($_POST as $key => $val)
{ if(!is_array($val)) $$key = html_entity_decode($val,ENT_QUOTES);
else $$key = $val;
}
if($ud_cart)
{ $reset =1;
$amt_cart[0] = $cart_id;
if(#$items) foreach($items as $key => $item )$amt_cart[] = $item;
$amt_cart = serialize($amt_cart);
}
if($reset)
{ // Initiated from the cart (tpl_cart.php on page load) to remove out-of-stock items
// from OLD CARTS -- where items have gone out-of-stock since cart created -- OR
// to simply update/remove cart items upon user request (user clicks Update|Remove)
if($amt_cart)
{ $amt_cart = stripslashes($amt_cart);
setcookie(AMART_CART, $amt_cart, time()+60*60*24*90, COOKIEPATH, COOKIE_DOMAIN);
}
exit;
}
// Create Cart, and add, update, or remove Cart-Items from within the catalog gallery && product detail pages
$add = array("product_id" => $product_id, "product_name" => $product_name, "product_type" => $product_type,"product_url" => $product_url,"qty" => $qty);
$update = "";
if( isset( $_COOKIE[AMART_CART] ) )
{ $amt_cart = stripslashes($_COOKIE[AMART_CART]);
$amt_cart = unserialize($amt_cart);
foreach($amt_cart as $key => $item)
{ if($key == 0 ) $amt_cart_id = $item;
else
{ foreach($item as $attr => $value)
{ if($product_id != $value) continue;
else
{ $update = 1;
if($qty == 0 )
{ unset($amt_cart[$key]);
break;
} else $amt_cart[$key]['qty'] = $qty;
}
}
}
}
if(!$update) $amt_cart[] = $add;
setcookie(AMART_CART, serialize($amt_cart), time()+60*60*24*90, COOKIEPATH, COOKIE_DOMAIN);
}
else
{ unset($_SESSION[STORE_ID]['dest_zip'], $_SESSION[STORE_ID]['dest_ctry']);
$amt_cart[0] = uniqid(AMART_CART);
$amt_cart[] = $add;
setcookie(AMART_CART, serialize($amt_cart), time()+60*60*24*90, COOKIEPATH, COOKIE_DOMAIN);
}
?>
checkout.php (works on WAMP, fails on LAMP)
<?php
// TPL CART POSTS VIA AJAX CALL IN cart.js
ob_start();
require_once(preg_replace("/wp-content.*/","wp-load.php",__FILE__));
ob_end_clean();
$_POST = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);
global $current_user, $wpfx;
$buyer_address1 = $buyer_address2 = $buyer_city = $buyer_region = $buyer_postal_code = $buyer_country = $buyer_ctry_code ="";
foreach ($_POST as $key => $val) $$key = $val;
foreach($buyer as $key => $val) $$key = $val;
$user_is_admin = current_user_can('manage_options');
if(!is_user_logged_in() || $user_is_admin )
{ if($userID = email_exists($email))
{ $user_info = $user_info = get_userdata($userID);
$user_login = $user_info->user_login;
$display_name = $user_info->display_name;
$welcome = "Welcome Back $display_name!";
}
if(#$welcome)
{ if(!$user_is_admin )
{ if(!$user_cnfm) die($welcome);
$auth = get_object_vars(wp_authenticate($user_login, $user_pass));
if(array_key_exists('errors',$auth)) die("Password Error");
wp_set_auth_cookie( $userID, true);
wp_set_current_user($userID, $user_login);
}
update_user_meta( $userID, 'customer', 1);
}
else
{ $buyer_name = "$buyer_first $buyer_last";
$ship_to_name = "$first_name $last_name";
if($ship_to_self)
{ foreach ( $ctry_opts as $key=>$value ) if (strcasecmp($country, $value) == 0) $buyer_country = $key;
$buyer_address1 = $address1;
$buyer_address2 = $address2;
$buyer_city = $city;
$buyer_region = $state;
$buyer_postal_code = $zip;
$buyer_ctry_code =strtolower($country);
} else foreach ( $ctry_opts as $key=>$value ) if ($buyer_ctry_code == $value) $buyer_country = $key;
$userdata = $user_cookie = array(
'user_login' => $email,
'user_email'=> $email,
'user_pass'=>$user_pass,
'first_name'=>$buyer_first,
'last_name'=>$buyer_last,
'display_name' =>$buyer_name,
'address1' => $buyer_address1,//null if not ship to self
'address2' => $buyer_address2,//null if not ship to self
'city' => $buyer_city,//google guess if not ship to self
'region' => $buyer_region,//google guess if not ship to self
'postal_code' => $buyer_postal_code,//null if not ship to self
'country' => $buyer_country,//google guess if not ship to self
'ctry_code' => $buyer_ctry_code,//google guess if not ship to self
'customer' => '1'
);
$userID = wp_insert_user( $userdata );
if(!$user_is_admin)
{ wp_set_auth_cookie( $userID, true);
wp_set_current_user($userID, $email);
}
unset($user_cookie['user_login'],$user_cookie['user_pass'],$user_cookie['display_name']);
setcookie('AMART_CUSTOMER', serialize($user_cookie), time()+60*60*24*180, COOKIEPATH, COOKIE_DOMAIN);
}
}
if(is_user_logged_in())
{ if(!$user_is_admin) $userID = $current_user->ID;
$cart_id = $item_name;
$cart = $wpdb->get_row("SELECT * FROM {$wpfx}amt_carts WHERE cart_id = '$cart_id'", ARRAY_A);
if( $cart['host_checkout'] && isset($store_options->paypal_live) && $store_options->paypal_live !=='false')
$host_checkout = true;
$ship_to = serialize( array('first_name' => $first_name,'last_name' => $last_name,'address1' => $address1,'address2' => $address2,'city' => $city, 'state' => $state,'postal_code' => $zip,'country' =>$country));
$attributes = array('ship_to' => $ship_to, 'customer_id'=>$userID, 'checkout_date'=>$now);
$where = array('cart_id' => $cart_id);
$wpdb->update("{$wpfx}amt_carts", $attributes,$where);
}
?>
This is, I believe, due to a difference in PHP configuration. I cannot tell you more without knowing the full list of POST variables, besides broad guidelines.
This is what I assume is causing the issue:
You're assigning $_POST[key] to $key. This is fine
You're then looping through $buyers. If $_POST["buyers"] was not set or not an array, this will throw a notice.
A notice is an echo. You are not in an output buffering context, which therefore causes the headers to also be sent. If the headers are sent and you later send a cookie or other header info, you get the warning you are getting.
One of your dev environments probably has error_reporting set to E_NONE. Check this in the PHP information. If set to E_NONE, your code will work. If not, you will get that message. Consider always checking for the existence and correct type of your functions. A good way to do so concisely is as follows:
foreach (((array)$buyers) as $v) {
if $buyers is undefined, you will get an empty array. If buyers had one element you will have an array with one element. Otherwise, you will get the array you had.
Okay...
As much as Sébastien's answer made good sense (and was even correct in some regard), and grateful as I am to him for pointing out that Notice level errors are essentially an echo causing headers to be sent, and for demonstrating a new way (to me) of ensuring an array exists in a foreach loop... the problem actually appears to stem from the differences between Linux and Windows newline characters, which I discovered when opening the hosted "cart_add.php" (from FileZilla ftp ) for editing in Notepad++. I was surprised to find extra newlines for every line of code. (Not the way the file was written). On a whim, I highlighted the first doubled newline, and replaced all with \n. Uploading the file (which had worked before on either stack) cart_add.php subsequently returned an error indicating something like no such function - phpob_start.
Aha!
On my windows box, coding in Notepad++ and comparing files in Beyond Compare, the hosted (Linux) files appear to be exact copies of the local source files, however file sizes tell a different story (local / windows files invariably larger) which I suspect is owed to the difference in newline characters (\n\r) in windows, and (\n) on linux.
Now, the problem I face is
Gaining an understanding of why replacing (in Notepad++) all doubled newlines with \n (Linux standard) cased the script to break.
Establishing a means of safeguarding against this issue in the future
but perhaps that is a matter for a separate post?
Hi everyone once again!
We need some help to develop and implement a multi-curl functionality into our crawler. We have a huge array of "links to be scanned" and we loop throw them with a Foreach.
Let's use some pseudo code to understand the logic:
1) While ($links_to_be_scanned > 0).
2) Foreach ($links_to_be_scanned as $link_to_be_scanned).
3) Scan_the_link() and run some other functions.
4) Extract the new links from the xdom.
5) Push the new links into $links_to_be_scanned.
5) Push the current link into $links_already_scanned.
6) Remove the current link from $links_to_be_scanned.
Now, we need to define a maximum number of parallel connections and be able to run this process for each link in parallel.
I understand that we're gonna have to create a $links_being_scanned or some kind of queue.
I'm really not sure how to approach this problem to be honest, if anyone could provide some snippet or idea to solve it, it would be greatly appreciated.
Thanks in advance!
Chris;
Extended:
I just realized that is not the multi-curl itself the tricky part, but the amount of operations done with each link after the request.
Even after the muticurl, I would eventually have to find a way to run all this operations in parallel. The whole algorithm described below would have to run in parallel.
So now rethinking, we would have to do something like this:
While (There's links to be scanned)
Foreach ($Link_to_scann as $link)
If (There's less than 10 scanners running)
Launch_a_new_scanner($link)
Remove the link from $links_to_be_scanned array
Push the link into $links_on_queue array
Endif;
And each scanner does (This should be run in parallel):
Create an object with the given link
Send a curl request to the given link
Create a dom and an Xdom with the response body
Perform other operations over the response body
Remove the link from the $links_on_queue array
Push the link into the $links_already_scanned array
I assume we could approach this creating a new PHP file with the scanner algorithm, and using pcntl_fork() for each parallel proccess?
Since even using multi-curl, I would eventually have to wait looping on a regular foreach structure for the other processes.
I assume I would have to approach this using fsockopen or pcntl_fork.
Suggestions, comments, partial solutions, and even a "good luck" will be more than appreciated!
Thanks a lot!
DISCLAIMER: This answer links an open-source project with which I'm involved. There. You've been warned.
The Artax HTTP client is a socket-based HTTP library that (among other things) offers custom control over the number of concurrent open socket connections to individual hosts while making multiple asynchronous HTTP requests.
Limiting the number of concurrent connections is easily accomplished. Consider:
<?php
use Artax\Client, Artax\Response;
require dirname(__DIR__) . '/autoload.php';
$client = new Client;
// Defaults to max of 8 concurrent connections per host
$client->setOption('maxConnectionsPerHost', 2);
$requests = array(
'so-home' => 'http://stackoverflow.com',
'so-php' => 'http://stackoverflow.com/questions/tagged/php',
'so-python' => 'http://stackoverflow.com/questions/tagged/python',
'so-http' => 'http://stackoverflow.com/questions/tagged/http',
'so-html' => 'http://stackoverflow.com/questions/tagged/html',
'so-css' => 'http://stackoverflow.com/questions/tagged/css',
'so-js' => 'http://stackoverflow.com/questions/tagged/javascript'
);
$onResponse = function($requestKey, Response $r) {
echo $requestKey, ' :: ', $r->getStatus();
};
$onError = function($requestKey, Exception $e) {
echo $requestKey, ' :: ', $e->getMessage();
}
$client->requestMulti($requests, $onResponse, $onError);
IMPORTANT: In the above example the Client::requestMulti method is making all the specified requests asynchronously. Because the per-host concurrency limit is set to 2, the client will open up new connections for the first two requests and subsequently reuse those same sockets for the other requests, queuing requests until one of the two sockets become available.
you could try something like this, haven't checked it, but you should get the idea
$request_pool = array();
function CreateHandle($url) {
$handle = curl_init($url);
// set curl options here
return $handle;
}
function Process($data) {
global $request_pool;
// do something with data
array_push($request_pool , CreateHandle($some_new_url));
}
function RunMulti() {
global $request_pool;
$multi_handle = curl_multi_init();
$active_request_pool = array();
$running = 0;
$active_request_count = 0;
$active_request_max = 10; // adjust as necessary
do {
$waiting_request_count = count($request_pool);
while(($active_request_count < $active_request_max) && ($waiting_request_count > 0)) {
$request = array_shift($request_pool);
curl_multi_add_handle($multi_handle , $request);
$active_request_pool[(int)$request] = $request;
$waiting_request_count--;
$active_request_count++;
}
curl_multi_exec($multi_handle , $running);
curl_multi_select($multi_handle);
while($info = curl_multi_info_read($multi_handle)) {
$curl_handle = $info['handle'];
call_user_func('Process' , curl_multi_getcontent($curl_handle));
curl_multi_remove_handle($multi_handle , $curl_handle);
curl_close($curl_handle);
$active_request_count--;
}
} while($active_request_count > 0 || $waiting_request_count > 0);
curl_multi_close($multi_handle);
}
You should look for some more robust solution to your problem. RabbitMQ
is a very good solution I used. There is also Gearman but I think it is your choice.
I prefer RabbitMQ.
I will share with you my code which I have used to collect email addresses from certain website.
You can modify it to fit your needs.
There were some problems with relative URL's there.
And I do not use CURL here.
<?php
error_reporting(E_ALL);
$home = 'http://kharkov-reklama.com.ua/jborudovanie/';
$writer = new RWriter('C:\parser_13-09-2012_05.txt');
set_time_limit(0);
ini_set('memory_limit', '512M');
function scan_page($home, $full_url, &$writer) {
static $done = array();
$done[] = $full_url;
// Scan only internal links. Do not scan all the internet!))
if (strpos($full_url, $home) === false) {
return false;
}
$html = #file_get_contents($full_url);
if (empty($html) || (strpos($html, '<body') === false && strpos($html, '<BODY') === false)) {
return false;
}
echo $full_url . '<br />';
preg_match_all('/([A-Za-z0-9_\-]+\.)*[A-Za-z0-9_\-]+#([A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9]\.)+[A-Za-z]{2,4}/', $html, $emails);
if (!empty($emails) && is_array($emails)) {
foreach ($emails as $email_group) {
if (is_array($email_group)) {
foreach ($email_group as $email) {
if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
$writer->write($email);
}
}
}
}
}
$regexp = "<a\s[^>]*href=(\"??)([^\" >]*?)\\1[^>]*>(.*)<\/a>";
preg_match_all("/$regexp/siU", $html, $matches, PREG_SET_ORDER);
if (is_array($matches)) {
foreach($matches as $match) {
if (!empty($match[2]) && is_scalar($match[2])) {
$url = $match[2];
if (!filter_var($url, FILTER_VALIDATE_URL)) {
$url = $home . $url;
}
if (!in_array($url, $done)) {
scan_page($home, $url, $writer);
}
}
}
}
}
class RWriter {
private $_fh = null;
private $_written = array();
public function __construct($fname) {
$this->_fh = fopen($fname, 'w+');
}
public function write($line) {
if (in_array($line, $this->_written)) {
return;
}
$this->_written[] = $line;
echo $line . '<br />';
fwrite($this->_fh, "{$line}\r\n");
}
public function __destruct() {
fclose($this->_fh);
}
}
scan_page($home, 'http://kharkov-reklama.com.ua/jborudovanie/', $writer);