Programmer needed for Subscription-based Protection Plugin

Discussion in 'Setting-up protection' started by matthewebel, Aug 18, 2008.

  1. matthewebel

    matthewebel Minister of Piano Rock

    Joined:
    Jul 13, 2008
    Messages:
    22
    I am rolling out a service where users can download new music each month as I make it... the problem right now is that the current protection plugins simply give a user access to a folder.

    I need a plugin that will restrict a user's downloads to only the files that have been uploaded since their membership went active (or within 1 month of their activation) so they can download only the latest additions and not the entire library.

    Any ideas? Anyone think they can write something like this?
  2. davidm1

    davidm1 aMember User & Partner

    Joined:
    May 16, 2006
    Messages:
    4,437
    There's nothing out of the box that will do this with amember. I call this a "book of the month" model. Definitely send in a request to amember to get this plugin made as I know lots of others want it too. Theres a lot of newsletter publishers who would find it very useful.

    David
  3. jimjwright

    jimjwright New Member

    Joined:
    Sep 12, 2007
    Messages:
    162
    Hello,

    If you have aMember Pro 3.1.2 and the Incremental Content Plugin you can modify the plugin so that is also does not show or make accessible thru mod_rewrite any content before payment begin date. The plugin already handles content in the future, the following mod also takes into account content in the past.

    The file that needs to be modified is amember/plugins/protect/php_include/check.inc.php

    The following line in function link_check_access() needs to be modified from
    the following:

    PHP:
      if ($link_start_delay_sec <= $now && $link_duration_sec >= $now)
    to

    PHP:
       ($link_start_delay_sec >= $begin_time && $link_start_delay_sec <= $now && $link_duration_sec >= $now)
    A similiar line in function user_get_links() needs to be modfied from the following:

    PHP:
      if ($link_start_delay_sec <= $now && $link_duration_sec >= $now)
    to

    PHP:
      if ($link_start_delay_sec >= $begin_time && $link_start_delay_sec <= $now && $link_duration_sec >= $now)
    Use at your own risk and backup file before modifying because this is a very important file. Seemed to work for me. You might have to play with the line a little if you want to give access to the current month or whatever you frequency of content update is.

    $begin_time is (least the way I took it from reading code) is the $begin_date of a active (non-expired) payment for the incremental content product. I'm not quite sure what will happen if you have gaps (i.e. renewal of product after expiration) if the user would then still have links to previous content or only from new payment date going forward. The expected behaviour would be for the user to always have links to incremental content that covered the payments paid for but I don't if this code will do that without further investigation or modifications. In other words if you multiple payment records for the product there might be more work involved to cover all payments correctly with correct links if that makes sense.

    Jimmy
  4. matthewebel

    matthewebel Minister of Piano Rock

    Joined:
    Jul 13, 2008
    Messages:
    22
    Jimjwright-

    Thanks for the idea... the problem is that, as far as I know, the incremental content plugin doesn't work with .htpaswd protection, only new_rewrite.

    Unfortunately, iTunes can't authenticate like that... it needs an .htpaswd based system of protection to deal with a protected podcast. Otherwise it just errors out.

    The Incremental Content Plugin also can't deal with content placed OUTSIDE the domain name of the site. My site is at matthewebel.net and my content is hosted higher up on the same server, matthewebelentertainment.com

    So I'm still kind of stuck here.
  5. celina

    celina Member

    Joined:
    Sep 9, 2008
    Messages:
    86
    this is pretty much exactly what i'm looking for but I can't test it with the demo version of the software. And if amember can't do this, then there's no point in my even purchasing it.

    I have played around with the incremental content plugin, and will play around with it some more. I hadn't realized that I could add links to content after s group of people had registered -- for instance, when a new issue of the magazine is created. I'll test that out today.

    As for your suggestions below -- anyone have this hack up and running? And is the purchased version of amember NOT ioncube encoded?
  6. jimjwright

    jimjwright New Member

    Joined:
    Sep 12, 2007
    Messages:
    162
    Hello,

    The purchased version I believe only encodes 1 file rconfig.inc.php. So with the purchased version you should be able to modify code to do what you need to do.

    Jimmy
  7. celina

    celina Member

    Joined:
    Sep 9, 2008
    Messages:
    86
    bought the program and plugin and going to give the above a try. Trying to figure out how to give access to currently published (magazine) as well, and how the line would be tweaked to do that. Hmmmm....
    Any suggestions?
  8. kirkward

    kirkward New Member

    Joined:
    Feb 12, 2008
    Messages:
    15
    I have a custom built application that provides incremental downloads (and more) in .htaccess protected folders. I can make three or four copies available if anyone wants to try it. PM me if you're interested.
  9. celina

    celina Member

    Joined:
    Sep 9, 2008
    Messages:
    86
    this hack is perfect, thank you so much!
    I am selling digital magazine subscriptions, so now when folks sign up they will only get access to magazine issues that are "published" AFTER they sign up.
    But I have one more issue: I also want them to immediately get access to the current issue.
    It took me a long time, but I finally got this working for the user_get_links function in check.inc.php. This is the function that displays links in the member area for the pieces of content users should have access to. I basically added a bit of code that would check for the difference in time between the day the user signed up and the day the link was added; if the amount was a positive (which would mean the link was added *before* the user signed up) it would find the piece of content for which this positive difference was the least amount of days (and thereby published just before the user signed up). It would add that piece of content to the list.

    It works, maybe not the most parsimonious solution, but here it is, if anyone needs that (lists link to current issue, but no issues before that):
    PHP:
    function user_get_links($products_begin_date)
    {
        global 
    $db;
        
        
    $now time();
        
    $links = array();
        if(!
    defined("INCREMENTAL_CONTENT_PLUGIN")) return $links;
        if (
    $products_begin_date)
        {
        echo 
    "oh hai i am products_begin_date".$products_begin_date."<br>";
            
    $links_query $db->query("SELECT * FROM {$db->config[prefix]}products_links WHERE link_product_id IN (".implode(",",array_keys($products_begin_date)).")");
            
    $least_time=20000000;
            while (
    $link mysql_fetch_assoc($links_query))
            {
                
    $begin_time strtotime($products_begin_date[$link['link_product_id']]['begin_date']);
                
    $link_start_delay_sec link_get_seconds($link['link_start_delay'], $begin_time);
                
    $link_duration_sec link_get_seconds($link['link_duration'], $link_start_delay_sec);
                
    $time_diff = ($begin_time $link_start_delay_sec);
                if (
    $link_start_delay_sec >= $begin_time && $link_start_delay_sec <= $now && $link_duration_sec >= $now)
                {
                    
    $links[$link['link_id']] = $link;
                }
        if ((
    $time_diff $least_time) && ($time_diff >= 0))
                    {
                    
    $least_time $time_diff;
                    
    $current_link $link;
                    
    $current_id $link['link_id'];
                    }
            }
            
        }
        if (
    $current_id 0){
        
    $links[$current_id] = $current_link;    
        }
        return 
    $links;
    }
    Unfortunately, the above does not really control access, but rather only controls the links that show up in the member area. SO now I'm trying to make the links_check_access part work, and am getting no joy. I know part of the problem is I don't really know php and am just trying to make my way through it based on other scripting languages I know. Every time it checks a link for access, I need to set up a loop like above that basically goes through all the products that are incremental content products, find the one that is closest in the past to the begin time, and add it to the "if" check. I can't figure out how to add that loop. anyone got any ideas? or think they can do this for me for some $$? I'm hoping to get this launched this week. Help!
  10. jimjwright

    jimjwright New Member

    Joined:
    Sep 12, 2007
    Messages:
    162
    Hello,

    I originally did hack awhile back. I intended for it to be used for like a monthly newsletter or subscription where you specified an absolute (or exact date) for start date of each added link like the following:

    If you are doing something like this then modify file amember/plugins/protect/php_include/check.inc.php as follows:

    PHP:
    function link_check_access($login$link_ids)
    {
        global 
    $db;
        
        if (!
    $link_ids) return false;
        if (
    $link_ids[0] == 'ONLY_LOGIN') return true;
        
    $link_id $link_ids[0];
        
    $link $db->query_first("SELECT * FROM {$db->config[prefix]}products_links WHERE link_id = '$link_id'");
        if (!
    $link) return false;
        
        
    $login $db->escape($login);
        
    $product_ids $link['link_product_id'];
        
    // first payment
        
    $begin_date $db->query_one("SELECT MIN(p.begin_date)
            FROM 
    {$db->config['prefix']}payments p
                LEFT JOIN 
    {$db->config['prefix']}members m USING (member_id)
            WHERE m.login = '
    $login'
                AND p.begin_date <= NOW()
                AND p.completed > 0
                AND p.product_id IN (
    $product_ids)");
        
    // check for active payment
        
    if (!($db->query_one("SELECT p.begin_date
            FROM 
    {$db->config['prefix']}payments p
                LEFT JOIN 
    {$db->config['prefix']}members m USING (member_id)
            WHERE m.login = '
    $login'
                AND p.begin_date <= NOW()
                AND p.expire_date >= NOW()
                AND p.completed > 0
                AND p.product_id IN (
    $product_ids)")))
        {
            return 
    false;
        }
        
        if (
    $begin_date)
        {
            
    $now time();
            
    $product $db->get_product($link['link_product_id']);
            
    $begin_date adjust_payment_date($begin_date);
            
    $begin_time strtotime($begin_date);
            
    $link_start_delay_sec link_get_seconds($link['link_start_delay'], $begin_time);
            
    $link_duration_sec link_get_seconds($link['link_duration'], $link_start_delay_sec);
            if (
    $link_start_delay_sec >= $begin_time && $link_start_delay_sec <= $now && $link_duration_sec >= $now)
            {
                return 
    true;
            } else {
                return 
    false;
            }
        } else {
            return 
    false;
        }
    }
        
    function 
    user_get_links($products_begin_date)
    {
        global 
    $db;
        
        
    $now time();
        
    $links = array();
        if(!
    defined("INCREMENTAL_CONTENT_PLUGIN")) return $links;
        if (
    $products_begin_date)
        {
            
    $links_query $db->query("SELECT * FROM {$db->config[prefix]}products_links WHERE link_product_id IN (".implode(",",array_keys($products_begin_date)).")");
            while (
    $link mysql_fetch_assoc($links_query))
            {
                
    $begin_date adjust_payment_date($products_begin_date[$link['link_product_id']]['begin_date']);
                
    $begin_time strtotime($begin_date);
                
    $link_start_delay_sec link_get_seconds($link['link_start_delay'], $begin_time);
                
    $link_duration_sec link_get_seconds($link['link_duration'], $link_start_delay_sec);
                if (
    $link_start_delay_sec >= $begin_time && $link_start_delay_sec <= $now && $link_duration_sec >= $now)
                {
                    
    $links[$link['link_id']] = $link;
                }
            }
        }    
        return 
    $links;
    }

    function 
    adjust_payment_date($date)
    {
        list(
    $y,$m,$d) = split('-'$date);
        
    $date date('Y-m-d'mktime(0,0,0,$m1$y));
        return 
    $date;
    }


    I added a function adjust_payment_date() that will take the users payment date and adjust it to the beginning of month. So if user purchases on January 13, 2009 it will make it appear that there payment date was January 1, 2009 so that they would get access to January newsletter if the start date for the January newsletter was January 1, 2009. My picture above was for 2008 but I think everybody gets the picture.

    If your not using exact (i.e. absolute dates) that are based on beginning of month then this solution will not work for you. Hope this helps.

    As always my disclaimer is use at your own risk and please backup this file before modifying, but it seemed to work for me with these modifications.

    Oh and finally that code snippet was from 3.1.2 code base. If 3.1.4 is different then you probably just want to merge the above changes into your code base instead of taking it as is or else when I get home tonight I can post the 3.1.4 mods.

    If this doesn't work for you celina then email me jwright@cowasoft.com with your specific needs and I can get it working for you hopefully.

    Jimmy
  11. celina

    celina Member

    Joined:
    Sep 9, 2008
    Messages:
    86
    Adjusted Date

    Jimmy, that example is really, helpful. i totally see how I could use one adjusted_begin_time function for use in both the Check_access function and the User_links functions.

    However, you're right, I'm not using exact dates, the magazine gets published on varying dates and with varying time lapses (approx. every two months, but not *exactly* 60 days or anything else).

    So I need to work on an adjusted_begin_time function that works like what I figured out above.

    Basically, here is how it would need to work:

    function adjusted_begin_time
    $least_time = 200000; //just setting the least time at an unreasonably high number to start
    for each incremental product
    {
    $time_difference = $begin_time - $product_start_time; //if this number is > 0, it means the product was published BEFORE the date this person ordered their subscription
    if (($time_difference > 0) and ($time_difference < $least_time))
    {
    $least_time = $time_difference; \\set least time to this amount
    $closest_product = this incremental product id; \\save this product id
    }
    }
    \\ once this for each or while loop is done, $closest_product should contain the id of the last product that was published before this user's begin_time
    $adjusted_begin_time = $product_begin_time[$closest_product];


    Okay, I kind of k now how to do all of this except for the foreach or while loop part. That's because I really don't know php at all. So, help anyone? Or else, Jimmy, if you're avail email me at debbie@bust.com and we'll see if you can do this for me.

    thanks!
  12. jimjwright

    jimjwright New Member

    Joined:
    Sep 12, 2007
    Messages:
    162
    Hello,

    In my example picture for the column "Link Available After" you see I'm using exact dates for when each newsletter becomes available. My products happen to be published on a monthly basis and are made available at first of month. Are you still using exact dates or are you using relative times for that column? If your using exact dates are you saying that they don't necessarily start at beginning of month but can vary and you just want to give the new purchaser access to the most recently published material?

    So if you have product(3) published as follows:

    Link 1: Published January 1, 2009
    Link 2: Published January 10, 2009
    Link 3: Published Feburary 1, 2009 (i.e. content already created but hidden)

    User joins Today (i.e. January 13, 2009) you want to give them access to Link 2 product, and all future products when there start time kicks in, but not Link 1 product.

    If this is what you need I can write some code to do this for you later tonight if someone has not already done it for you.

    What version of amember are you using? I have every version from 3.0.9 and later. Let me know which version I should modify.

    Jimmy
  13. celina

    celina Member

    Joined:
    Sep 9, 2008
    Messages:
    86
    yes, issues become available on exact dates, and the scenario you describe above is exactly what I need. The method and logic i describe above should work well, i already have it working like a charm for the user_links function (it only shows the correct links) but I need it to work for the check_access function as well, and I don't know how to set up a "while" loop grabbing values from the database. I am using version 3.1.4.
    Also, I can not figure out what the benefit of gathering incremental links into groups is??
  14. jimjwright

    jimjwright New Member

    Joined:
    Sep 12, 2007
    Messages:
    162
    Hello,

    It looks like things changed between 3.1.2 and 3.1.4. I got it to work on 3.1.2 but am not setup to test on 3.1.4. So you might have issues but try to modify link_check_access() with following:

    PHP:
    if ($begin_date)
    {
      
    $nearest_link_id FindNearestLinkToProductPaymentDate($product_id$begin_date);
      if (
    $nearest_link_id != && $nearest_link_id == $link_ids[0])
        return 
    true;
      
    $now time();
      
    $product $db->get_product($link[$k]['link_product_id']);
      
    $begin_time strtotime($begin_date);
      
    $link_start_delay_sec link_get_seconds($link[$k]['link_start_delay'], $begin_time);
      
    $link_duration_sec link_get_seconds($link[$k]['link_duration'], $link_start_delay_sec);
      if (
    $link_start_delay_sec >= $begin_time && $link_start_delay_sec <= $now && $link_duration_sec >= $now)
      {
        return 
    true;
      } else {
        continue;
      }
    } else {
      continue;
    }

    Basically the following 3 lines were added to routine

    PHP:
      $nearest_link_id FindNearestLinkToProductPaymentDate($product_id$begin_date);
      if (
    $nearest_link_id != && $nearest_link_id == $link_ids[0])
        return 
    true;
    And the following line was modified in order to not allow access to previously published work:

    PHP:
    if ($link_start_delay_sec >= $begin_time && $link_start_delay_sec <= $now && $link_duration_sec >= $now)

    And add the following new function below it:

    PHP:
    function FindNearestLinkToProductPaymentDate($product_id$begin_date)
    {
      global 
    $db;

      
    $link_id 0;
      
    $links_query $db->query("SELECT * FROM {$db->config[prefix]}products_links WHERE link_product_id = '$product_id'");
      if (!
    mysql_num_rows($links_query))
        return 
    $link_id;

      
    $nearest_time=20000000
      
    $begin_time strtotime($begin_date); 
      while (
    $link mysql_fetch_assoc($links_query))
      {
        
    $link_start_delay_sec link_get_seconds($link['link_start_delay'], $begin_time); 
        
    $link_duration_sec    link_get_seconds($link['link_duration'], $link_start_delay_sec); 
        
    $time_diff = ($begin_time $link_start_delay_sec); 
        if ((
    $time_diff $nearest_time) && ($time_diff >= 0)) 
        {
          
    $nearest_time $time_diff
          
    $link_id $link['link_id']; 
        } 
      }

      return 
    $link_id;
    }
    This function tries to find the nearest published link to the product before the product purchase date. This routine is similar to your other code with a db access to find the records to check against.

    Jimmy
  15. celina

    celina Member

    Joined:
    Sep 9, 2008
    Messages:
    86
    it WORKS!!!! Thank you soooo much! You are a lifesaver. I really really appreciate the help. And I'm sure this will be useful for others looking for this functionality as well. I am so grateful!
  16. jimjwright

    jimjwright New Member

    Joined:
    Sep 12, 2007
    Messages:
    162
    Congrats I'm glad we got it working for you. You did most of the work. Good luck with your site and your digital subscriptions !!!

    Oh yeah, now that you have custom code, in the future if you upgrade aMember you will have to re-sync this custom code.

    Its best to take notes now and write down all files modified to help with this task in the future.

    Jimmy
  17. sharris203

    sharris203 New Member

    Joined:
    Feb 27, 2009
    Messages:
    45
    I have ONE more need for this.

    Is there a way to make ALL back content available after the user has been a member for 1 month??

    That way i could do a free trial with digital product and they'd only get the current months downloads, but after I charge them, then all the downloads would be accessible.

    [I just thought about it. After 1 month, i could time release 1 page with a list of the downloads on it.
    But, how my site is currently set up, all the protected links are on the main page and clickable (which prompt them to login/register).
    From what I've read here, the old content folder would not be protected - is that correct? So I can't show the download links to the public anymore.]
  18. alexander

    alexander Administrator Staff Member

    Joined:
    Jan 8, 2003
    Messages:
    6,279
    You can use Incremental Content plugin for this.
    Place old content into separate folder and make it available after one month.
    You can still use links on your public site, when user who should not have access yet will click on link, he will get and access denied error.

Share This Page